package udpsprotocol import "testing" // A packet older than one already delivered carries an older time base. Its // samples land on top of data that is already in the ring and leave the span // they should have filled empty, so it must not get through. func TestSequenceGateRejectsStaleAndDuplicate(t *testing.T) { var g SequenceGate if ok, lost := g.Accept(10); !ok || lost != 0 { t.Fatalf("first packet: got (%v, %d), want (true, 0)", ok, lost) } if ok, _ := g.Accept(11); !ok { t.Fatal("counter 11 advances past 10 and must be accepted") } if ok, _ := g.Accept(9); ok { t.Error("counter 9 is older than the delivered 11 and must be dropped") } if ok, _ := g.Accept(11); ok { t.Error("a repeat of the delivered counter must be dropped") } if g.Stale != 2 { t.Errorf("Stale = %d, want 2", g.Stale) } // The rejections must not have moved the sequence on. if ok, lost := g.Accept(12); !ok || lost != 0 { t.Errorf("after rejections: got (%v, %d), want (true, 0)", ok, lost) } } // The loss count is what lets a consumer tell a widened gap from a slowed // producer, so it must exclude the packet being delivered and must not persist // into the next one. func TestSequenceGateReportsLoss(t *testing.T) { var g SequenceGate g.Accept(100) if _, lost := g.Accept(104); lost != 3 { t.Errorf("101..103 missing: lost = %d, want 3", lost) } if _, lost := g.Accept(105); lost != 0 { t.Errorf("consecutive packet: lost = %d, want 0", lost) } if g.Stale != 0 { t.Errorf("Stale = %d, want 0", g.Stale) } } // The counter is a wrapping uint32. Ordering it by plain comparison would call // every packet after the wrap older than 0xFFFFFFFF and kill the stream. func TestSequenceGateSurvivesWraparound(t *testing.T) { var g SequenceGate for _, c := range []uint32{0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFF, 0, 1, 2} { ok, lost := g.Accept(c) if !ok { t.Fatalf("counter %#x rejected across the wrap", c) } if lost != 0 { t.Errorf("counter %#x: lost = %d, want 0", c, lost) } } // Loss must still be measured correctly across the wrap. var h SequenceGate h.Accept(0xFFFFFFFE) if _, lost := h.Accept(1); lost != 2 { t.Errorf("0xFFFFFFFF and 0 missing: lost = %d, want 2", lost) } } // A reconnect restarts the producer's counter independently of ours; a carried // over counter would reject the entire new stream. func TestSequenceGateResetAcceptsLowerCounter(t *testing.T) { var g SequenceGate g.Accept(5000) g.Reset() if ok, lost := g.Accept(3); !ok || lost != 0 { t.Errorf("after Reset: got (%v, %d), want (true, 0)", ok, lost) } }