github.com/randomizedcoder/goTrackRTP@v0.0.2/trackRTP_test.go (about) 1 package goTrackRTP 2 3 // https://github.com/randomizedcoder/goTrackRTP/ 4 5 // See also: https://dave.cheney.net/2019/05/07/prefer-table-driven-tests 6 7 import ( 8 "math" 9 "os" 10 "reflect" 11 "testing" 12 _ "unsafe" 13 ) 14 15 // unsafe for fastrand 16 17 const ( 18 debugLevelCst = 11 19 WindowSizeTestingCst = 100 20 ) 21 22 // unsafe for the FastRand() 23 //_ "unsafe" 24 // //go:linkname FastRand runtime.fastrand 25 // func FastRand() uint32 26 27 // // https://cs.opensource.google/go/go/+/master:src/runtime/stubs.go;l=151?q=FastRandN&ss=go%2Fgo 28 // // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ 29 30 // //go:linkname FastRandN runtime.fastrandn 31 // func FastRandN(n uint32) uint32 32 33 func TestTrackerInit(t *testing.T) { 34 35 type test struct { 36 aw uint16 37 bw uint16 38 ab uint16 39 bb uint16 40 err error 41 Window uint16 42 Len int 43 } 44 45 tests := []test{ 46 // basic 47 {10, 10, 10, 10, nil, 10 + 10, 0}, 48 {100, 100, 100, 100, nil, 200, 0}, 49 {1500, 1500, 1500, 1500, nil, 1500 + 1500, 0}, 50 {10, 20, 10, 10, nil, 10 + 20, 0}, 51 52 // errors 53 {1, 10, 10, 10, ErrWindowAWMin, 0, 0}, 54 {1501, 10, 10, 10, ErrWindowAWMax, 0, 0}, 55 {10, 1, 10, 10, ErrWindowBWMin, 0, 0}, 56 {10, 1501, 10, 10, ErrWindowBWMax, 0, 0}, 57 {10, 10, 1, 10, ErrWindowABMin, 0, 0}, 58 {10, 10, 1501, 10, ErrWindowABMax, 0, 0}, 59 {10, 10, 10, 1, ErrWindowBBMin, 0, 0}, 60 {10, 10, 10, 1501, ErrWindowBBMax, 0, 0}, 61 62 // window too small 63 {0, 0, 0, 0, ErrWindowAWMin, 0, 0}, 64 {1, 1, 1, 1, ErrWindowAWMin, 0, 0}, 65 {3, 3, 3, 3, ErrWindowAWMin, 0, 0}, 66 {1501, 1501, 1501, 1501, ErrWindowAWMax, 0, 0}, 67 {1501, 1501, 1501, 1501, ErrWindowAWMax, 0, 0}, 68 } 69 70 for i, tc := range tests { 71 72 t.Logf("%s i:%d, tc: %v\n", t.Name(), i, tc) 73 74 tr, err := New(tc.aw, tc.bw, tc.ab, tc.bb, debugLevelCst) 75 76 if err != tc.err { 77 t.Fatalf("%s, err:%v != tc.err:%v", t.Name(), err, tc.err) 78 } 79 80 if err == nil { 81 if tr.Window != tc.Window { 82 t.Fatalf("%s, tr.Window:%d != tc.Window:%d", t.Name(), tr.Window, tc.Window) 83 } 84 85 if tr.Len() != tc.Len { 86 t.Fatalf("%s, etr.Len():%d != tc.Len:%d", t.Name(), tr.Len(), tc.Len) 87 } 88 } 89 } 90 } 91 92 func TestTrackerWindow(t *testing.T) { 93 94 type test struct { 95 aw uint16 96 bw uint16 97 ab uint16 98 bb uint16 99 m uint16 100 seq uint16 101 err error 102 Window uint16 103 Len int 104 Max uint16 105 Jump uint16 106 Position int 107 Category int 108 SubCategory int 109 } 110 111 tests := []test{ 112 // position duplicate 113 {10, 10, 10, 10, 0, 0, nil, 10 + 10, 1, 0, 0, PositionDuplicate, CategoryUnknown, SubCategoryUnknown}, 114 {10, 10, 10, 10, 1, 1, nil, 10 + 10, 1, 1, 0, PositionDuplicate, CategoryUnknown, SubCategoryUnknown}, 115 {10, 10, 10, 10, maxUint16, maxUint16, nil, 10 + 10, 1, maxUint16, 0, PositionDuplicate, CategoryUnknown, SubCategoryUnknown}, 116 {10, 10, 10, 10, maxUint16 - 1, maxUint16 - 1, nil, 10 + 10, 1, maxUint16 - 1, 0, PositionDuplicate, CategoryUnknown, SubCategoryUnknown}, 117 {100, 100, 100, 100, 0, 0, nil, 100 + 100, 1, 0, 0, PositionDuplicate, CategoryUnknown, SubCategoryUnknown}, 118 // position ahead - window 119 {10, 10, 10, 10, 0, 1, nil, 10 + 10, 2, 1, 1, PositionAhead, CategoryWindow, SubCategoryNext}, // failing here! max not updating 120 {10, 10, 10, 10, 0, 10, nil, 10 + 10, 2, 10, 10, PositionAhead, CategoryWindow, SubCategoryJump}, 121 {100, 100, 100, 100, 0, 1, nil, 100 + 100, 2, 1, 1, PositionAhead, CategoryWindow, SubCategoryNext}, 122 {100, 100, 100, 100, 0, 10, nil, 100 + 100, 2, 10, 10, PositionAhead, CategoryWindow, SubCategoryJump}, 123 {100, 100, 100, 100, 0, 100, nil, 100 + 100, 2, 100, 100, PositionAhead, CategoryWindow, SubCategoryJump}, 124 // position ahead - buffer 125 {10, 10, 10, 10, 0, 11, nil, 10 + 10, 1, 0, 0, PositionAhead, CategoryBuffer, SubCategoryUnknown}, 126 {10, 10, 10, 10, 0, 15, nil, 10 + 10, 1, 0, 0, PositionAhead, CategoryBuffer, SubCategoryUnknown}, 127 {10, 10, 10, 10, 0, 19, nil, 10 + 10, 1, 0, 0, PositionAhead, CategoryBuffer, SubCategoryUnknown}, 128 {10, 10, 10, 10, 0, 20, nil, 10 + 10, 1, 0, 0, PositionAhead, CategoryBuffer, SubCategoryUnknown}, 129 {100, 100, 100, 100, 0, 101, nil, 100 + 100, 1, 0, 0, PositionAhead, CategoryBuffer, SubCategoryUnknown}, 130 {100, 100, 100, 100, 0, 200, nil, 100 + 100, 1, 0, 0, PositionAhead, CategoryBuffer, SubCategoryUnknown}, 131 // position ahead - restart 132 {10, 10, 10, 10, 0, 21, nil, 10 + 10, 1, 21, 0, PositionAhead, CategoryRestart, SubCategoryUnknown}, 133 {10, 10, 10, 10, 0, 100, nil, 10 + 10, 1, 100, 0, PositionAhead, CategoryRestart, SubCategoryUnknown}, 134 {10, 10, 10, 10, 0, 1000, nil, 10 + 10, 1, 1000, 0, PositionAhead, CategoryRestart, SubCategoryUnknown}, 135 {100, 100, 100, 100, 0, 201, nil, 100 + 100, 1, 201, 0, PositionAhead, CategoryRestart, SubCategoryUnknown}, 136 {100, 100, 100, 100, 0, 1000, nil, 100 + 100, 1, 1000, 0, PositionAhead, CategoryRestart, SubCategoryUnknown}, 137 // position ahead - window 138 139 // - note because we only insert x2 in this test, we can't test PositionAhead + SubCategoryDuplicate 140 // position behind - window 141 {10, 10, 10, 10, 0, maxUint16, nil, 10 + 10, 2, 0, 1, PositionBehind, CategoryWindow, SubCategoryUnknown}, 142 {10, 10, 10, 10, 0, maxUint16 - 5, nil, 10 + 10, 2, 0, 6, PositionBehind, CategoryWindow, SubCategoryUnknown}, 143 {10, 10, 10, 10, 0, maxUint16 - 9, nil, 10 + 10, 2, 0, 10, PositionBehind, CategoryWindow, SubCategoryUnknown}, 144 {100, 100, 100, 100, 0, maxUint16, nil, 100 + 100, 2, 0, 1, PositionBehind, CategoryWindow, SubCategoryUnknown}, 145 // position behind - buffer 146 {10, 10, 10, 10, 0, maxUint16 - 10, nil, 10 + 10, 1, 0, 0, PositionBehind, CategoryBuffer, SubCategoryUnknown}, 147 {10, 10, 10, 10, 0, maxUint16 - 11, nil, 10 + 10, 1, 0, 0, PositionBehind, CategoryBuffer, SubCategoryUnknown}, 148 {10, 10, 10, 10, 0, maxUint16 - 19, nil, 10 + 10, 1, 0, 0, PositionBehind, CategoryBuffer, SubCategoryUnknown}, 149 {100, 100, 100, 100, 0, maxUint16 - 100, nil, 100 + 100, 1, 0, 0, PositionBehind, CategoryBuffer, SubCategoryUnknown}, 150 {100, 100, 100, 100, 0, maxUint16 - 199, nil, 100 + 100, 1, 0, 0, PositionBehind, CategoryBuffer, SubCategoryUnknown}, 151 // position behind - restart 152 {10, 10, 10, 10, 0, maxUint16 - 20, nil, 10 + 10, 1, maxUint16 - 20, 0, PositionBehind, CategoryRestart, SubCategoryUnknown}, 153 {10, 10, 10, 10, 0, maxUint16 - 100, nil, 10 + 10, 1, maxUint16 - 100, 0, PositionBehind, CategoryRestart, SubCategoryUnknown}, 154 {10, 10, 10, 10, 0, maxUint16 - 1000, nil, 10 + 10, 1, maxUint16 - 1000, 0, PositionBehind, CategoryRestart, SubCategoryUnknown}, 155 {100, 100, 100, 100, 0, maxUint16 - 200, nil, 100 + 100, 1, maxUint16 - 200, 0, PositionBehind, CategoryRestart, SubCategoryUnknown}, 156 } 157 158 for i, tc := range tests { 159 160 t.Logf("%s i:%d, tc: %v\n", t.Name(), i, tc) 161 162 tr, err := New(tc.aw, tc.bw, tc.ab, tc.bb, debugLevelCst) 163 if err != tc.err { 164 t.Fatalf("%s, err:%v != tc.err:%v", t.Name(), err, tc.err) 165 } 166 167 _, e := tr.PacketArrival(tc.m) 168 if e != nil { 169 t.Fatalf("%s, err != nil:%v", t.Name(), e) 170 } 171 172 tax, et := tr.PacketArrival(tc.seq) 173 if et != nil { 174 t.Fatalf("%s, err != nil:%v", t.Name(), et) 175 } 176 177 if !reflect.DeepEqual(tr.Window, tc.Window) { 178 t.Fatalf("%s, test:%d !reflect.DeepEqual(tr.Window:%v, tc.Window:%v)", t.Name(), i, tr.Window, tc.Window) 179 } 180 181 if !reflect.DeepEqual(tax.Len, tc.Len) { 182 t.Fatalf("%s, test:%d !reflect.DeepEqual(tax.Len:%v, tc.Len:%v)", t.Name(), i, tax.Len, tc.Len) 183 } 184 185 if !reflect.DeepEqual(tr.Max(), tc.Max) { 186 t.Fatalf("%s, test:%d !reflect.DeepEqual(tr.Max():%v, tc.Max:%v)", t.Name(), i, tr.Max(), tc.Max) 187 } 188 189 if !reflect.DeepEqual(tax.Jump, tc.Jump) { 190 t.Fatalf("%s, test:%d !reflect.DeepEqual(tax.Jump:%v, tc.Jump:%v)", t.Name(), i, tax.Jump, tc.Jump) 191 } 192 193 if !reflect.DeepEqual(tax.Position, tc.Position) { 194 t.Fatalf("%s, test:%d !reflect.DeepEqual(tax.Position:%v, tc.Position:%v)", t.Name(), i, tax.Position, tc.Position) 195 } 196 if !reflect.DeepEqual(tax.Categroy, tc.Category) { 197 t.Fatalf("%s, test:%d !reflect.DeepEqual(tax.Categroy:%v, tc.Category:%v)", t.Name(), i, tax.Categroy, tc.Category) 198 } 199 if !reflect.DeepEqual(tax.SubCategory, tc.SubCategory) { 200 t.Fatalf("%s, test:%d !reflect.DeepEqual(tax.SubCategory:%v, tc.SubCategory:%v)", t.Name(), i, tax.SubCategory, tc.SubCategory) 201 } 202 } 203 } 204 205 func TestLongRunningWindow(t *testing.T) { 206 207 type test struct { 208 aw uint16 209 bw uint16 210 ab uint16 211 bb uint16 212 dl int 213 start uint16 214 err error 215 loops int64 216 Len int 217 } 218 219 tests := []test{ 220 {10, 10, 10, 10, 11, 0, nil, 21, 20}, 221 {10, 10, 10, 10, 11, 0, nil, 41, 20}, 222 {10, 10, 10, 10, 11, maxUint16 - 10, nil, 41, 20}, 223 {100, 100, 100, 100, 11, 0, nil, 201, 200}, 224 {100, 100, 100, 100, 11, 0, nil, 401, 200}, 225 {100, 100, 100, 100, 11, maxUint16 - 100, nil, 401, 200}, 226 {1000, 1000, 1000, 1000, 11, 0, nil, 2001, 2000}, 227 {1000, 1000, 1000, 1000, 11, 0, nil, 4001, 2000}, 228 {1000, 1000, 1000, 1000, 11, maxUint16 - 1000, nil, 4001, 2000}, 229 // long 230 {10, 10, 10, 10, 0, 0, nil, (math.MaxInt32 * 2) + 21, 20}, 231 {100, 100, 100, 100, 0, 0, nil, (math.MaxInt32 * 2) + 201, 200}, 232 {100, 100, 100, 100, 11, 0, nil, (math.MaxInt32 * 2) + 201, 200}, 233 } 234 235 if os.Getenv("LONG") != "true" { 236 t.Skip("Skipping long test. Set 'LONG=true' env var to run this") 237 } 238 239 for i, tc := range tests { 240 241 t.Logf("%s i:%d, tc: %v\n", t.Name(), i, tc) 242 243 tr, err := New(tc.aw, tc.bw, tc.ab, tc.bb, tc.dl) 244 if err != tc.err { 245 t.Fatalf("%s, err:%v != tc.err:%v", t.Name(), err, tc.err) 246 } 247 248 var tax *Taxonomy 249 var e error 250 var loops int64 251 var j uint16 = tc.start 252 for { 253 if tc.dl > 10 { 254 t.Logf("%s i:%d, tc: %v, j:%d, loops:%d\n", t.Name(), i, tc, j, loops) 255 } 256 tax, e = tr.PacketArrival(j) 257 if e != nil { 258 t.Fatalf("%s, e != nil:%v", t.Name(), e) 259 } 260 j++ 261 loops++ 262 if loops > tc.loops { 263 t.Logf("loops:%d > tc.Loops:%d, tr.Max():%d, tax.Len:%d, tr.Min():%d", loops, tc.loops, tr.Max(), tax.Len, tr.Min()) 264 if tc.dl > 110 { 265 t.Logf("items:%v", tr.itemsDescending()) 266 } 267 break 268 } 269 } 270 if !reflect.DeepEqual(tax.Len, tc.Len) { 271 t.Fatalf("%s, test:%d !reflect.DeepEqual(tax.Len:%v, tc.Len:%v)", t.Name(), i, tax.Len, tc.Len) 272 } 273 } 274 } 275 276 func TestLongRunningBackwardDuplicates(t *testing.T) { 277 278 type test struct { 279 aw uint16 280 bw uint16 281 ab uint16 282 bb uint16 283 dl int 284 start uint16 285 err error 286 loops int64 287 MaxRandJump uint32 288 Len int 289 } 290 291 debugL := 0 292 293 tests := []test{ 294 {10, 10, 10, 10, debugL, 0, nil, 21, 10, 20}, 295 {10, 10, 10, 10, debugL, 0, nil, 41, 10, 20}, 296 {10, 10, 10, 10, debugL, maxUint16 - 10, nil, 41, 10, 20}, 297 {100, 100, 100, 100, debugL, 0, nil, 201, 100, 200}, 298 {100, 100, 100, 100, debugL, 0, nil, 401, 100, 200}, 299 {100, 100, 100, 100, debugL, maxUint16 - 100, nil, 401, 100, 200}, 300 {1000, 1000, 1000, 1000, debugL, 0, nil, 2001, 1000, 2000}, 301 {1000, 1000, 1000, 1000, debugL, 0, nil, 4001, 1000, 2000}, 302 {1000, 1000, 1000, 1000, debugL, maxUint16 - 1000, nil, 4001, 1000, 2000}, 303 // long 304 {10, 10, 10, 10, 0, 0, nil, (int64(maxUint16) * 3) + 21, 10, 20}, 305 {100, 100, 100, 100, 0, 0, nil, (int64(maxUint16) * 3) + 201, 100, 200}, 306 {100, 100, 100, 100, 0, 0, nil, (int64(maxUint16) * 3) + 201, 100, 200}, 307 } 308 309 if os.Getenv("LONG") != "true" { 310 t.Skip("Skipping long test. Set 'LONG=true' env var to run this") 311 } 312 313 for i, tc := range tests { 314 315 t.Logf("%s i:%d, tc: %v\n", t.Name(), i, tc) 316 317 tr, err := New(tc.aw, tc.bw, tc.ab, tc.bb, tc.dl) 318 if err != tc.err { 319 t.Fatalf("%s, err:%v != tc.err:%v", t.Name(), err, tc.err) 320 } 321 322 var tax *Taxonomy 323 var e error 324 var loops int64 325 var j uint16 = tc.start 326 var dupSent int 327 var dup int 328 for { 329 if tc.dl > 10 { 330 t.Logf("%s i:%d, tc: %v, j:%d, loops:%d", t.Name(), i, tc, j, loops) 331 } 332 tax, e = tr.PacketArrival(j) 333 if e != nil { 334 t.Fatalf("%s, e != nil:%v", t.Name(), e) 335 } 336 if loops > int64(tc.MaxRandJump) { 337 if tax.SubCategory != SubCategoryNext { 338 t.Fatalf("%s, test:%d tax.SubCategory:%v != SubCategoryNext:%v", t.Name(), i, tax.SubCategory, SubCategoryNext) 339 } 340 341 // send a duplicate in the behind window 342 r := uint16(FastRandN(tc.MaxRandJump-1) + 1) // FastRandN can return zero (0) 343 if tc.dl > 10 { 344 t.Logf("%s i:%d, r:%d, j - r:%d", t.Name(), i, r, j-r) 345 } 346 tax, e = tr.PacketArrival(j - r) 347 if e != nil { 348 t.Fatalf("%s, e != nil:%v", t.Name(), e) 349 } 350 dupSent++ 351 if tax.SubCategory == SubCategoryDuplicate { 352 dup++ 353 } else { 354 t.Fatalf("%s, test:%d tax.SubCategory != SubCategoryDuplicate", t.Name(), i) 355 } 356 } 357 358 j++ 359 loops++ 360 if loops > tc.loops { 361 t.Logf("loops:%d > tc.Loops:%d, tr.Max():%d, tax.Len:%d, tr.Min():%d", loops, tc.loops, tr.Max(), tax.Len, tr.Min()) 362 if tc.dl > 110 { 363 t.Logf("items:%v", tr.itemsDescending()) 364 } 365 break 366 } 367 368 if tc.dl > 10 { 369 if loops%int64(maxUint16) == 0 { 370 t.Logf("loops:%d > tc.Loops:%d, tr.Max():%d, tax.Len:%d, tr.Min():%d", loops, tc.loops, tr.Max(), tax.Len, tr.Min()) 371 } 372 } 373 } 374 // if !reflect.DeepEqual(tax.Len, tc.Len) { 375 // t.Fatalf("%s, test:%d !reflect.DeepEqual(tax.Len:%v, tc.Len:%v)", t.Name(), i, tax.Len, tc.Len) 376 // } 377 if dupSent != dup { 378 t.Fatalf("%s, test:%d dupSent:%d != dup:%d", t.Name(), i, dupSent, dup) 379 } else { 380 t.Logf("%s i:%d, tc: %v, j:%d, loops:%d, duplicate test succeeded! dup:%d", t.Name(), i, tc, j, loops, dup) 381 } 382 } 383 } 384 385 func TestLongRunningSkipSend(t *testing.T) { 386 387 type test struct { 388 aw uint16 389 bw uint16 390 ab uint16 391 bb uint16 392 dl int 393 start uint16 394 err error 395 loops int64 396 SkipMod int 397 MaxSkip int 398 Len int 399 } 400 401 debugL := 11 402 403 tests := []test{ 404 {10, 10, 10, 10, debugL, 0, nil, 10, 2, 3, 10}, 405 {10, 10, 10, 10, debugL, 0, nil, 10, 3, 3, 10}, 406 {10, 10, 10, 10, debugL, maxUint16 - 10, nil, 10, 5, 3, 10}, 407 {100, 100, 100, 100, debugL, 0, nil, 100, 2, 3, 100}, 408 {100, 100, 100, 100, debugL, 0, nil, 100, 3, 3, 100}, 409 {100, 100, 100, 100, debugL, maxUint16 - 100, nil, 100, 5, 3, 100}, 410 {1000, 1000, 1000, 1000, debugL, 0, nil, 1000, 10, 2, 1000}, 411 {1000, 1000, 1000, 1000, debugL, 0, nil, 1000, 20, 3, 1000}, 412 {1000, 1000, 1000, 1000, debugL, maxUint16 - 1000, nil, 1000, 50, 10, 1000}, 413 } 414 415 if os.Getenv("LONG") != "true" { 416 t.Skip("Skipping long test. Set 'LONG=true' env var to run this") 417 } 418 419 for i, tc := range tests { 420 421 t.Logf("%s i:%d, tc: %v\n", t.Name(), i, tc) 422 423 tr, err := New(tc.aw, tc.bw, tc.ab, tc.bb, tc.dl) 424 if err != tc.err { 425 t.Fatalf("%s, err:%v != tc.err:%v", t.Name(), err, tc.err) 426 } 427 428 var tax *Taxonomy 429 var e error 430 var loops int64 431 var j uint16 = tc.start 432 var skip int 433 for { 434 if tc.dl > 10 { 435 t.Logf("%s i:%d, tc: %v, j:%d, loops:%d", t.Name(), i, tc, j, loops) 436 } 437 if loops%int64(tc.SkipMod) == 0 && skip < tc.MaxSkip { 438 t.Logf("%s i:%d, loops:%d, j:%d, skip:%d", t.Name(), i, loops, j, skip) 439 skip++ 440 } else { 441 tax, e = tr.PacketArrival(j) 442 if e != nil { 443 t.Fatalf("%s, e != nil:%v", t.Name(), e) 444 } 445 } 446 447 j++ 448 loops++ 449 if loops > tc.loops { 450 t.Logf("loops:%d > tc.Loops:%d, tr.Max():%d, tax.Len:%d, tr.Min():%d", loops, tc.loops, tr.Max(), tax.Len, tr.Min()) 451 if tc.dl > 110 { 452 t.Logf("items:%v", tr.itemsDescending()) 453 } 454 break 455 } 456 457 if tc.dl > 10 { 458 if loops%int64(maxUint16) == 0 { 459 t.Logf("loops:%d > tc.Loops:%d, tr.Max():%d, tax.Len:%d, tr.Min():%d", loops, tc.loops, tr.Max(), tax.Len, tr.Min()) 460 } 461 } 462 } 463 if !reflect.DeepEqual(tax.Len-1, tc.Len-skip) { 464 t.Fatalf("%s, test:%d !reflect.DeepEqual(tax.Len-1:%v, tc.Len:%v), skip:%d", t.Name(), i, tax.Len-1, tc.Len-skip, skip) 465 } 466 } 467 } 468 469 //go:linkname FastRand runtime.fastrand 470 func FastRand() uint32 471 472 // https://cs.opensource.google/go/go/+/master:src/runtime/stubs.go;l=151?q=FastRandN&ss=go%2Fgo 473 // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ 474 475 //go:linkname FastRandN runtime.fastrandn 476 func FastRandN(n uint32) uint32