@@ -24,7 +24,11 @@ package smux
2424
2525import (
2626 "container/heap"
27+ "fmt"
28+ "math/rand"
29+ "sync"
2730 "testing"
31+ "time"
2832)
2933
3034func TestShaper (t * testing.T ) {
@@ -70,3 +74,189 @@ func TestShaper2(t *testing.T) {
7074 t .Log ("sid:" , w .frame .sid , "seq:" , w .seq )
7175 }
7276}
77+
78+ func TestShaperQueueFairness (t * testing.T ) {
79+ rand .Seed (time .Now ().UnixNano ())
80+
81+ sq := NewShaperQueue ()
82+
83+ const streams = 10
84+ const testDuration = 10 * time .Second
85+
86+ var wg sync.WaitGroup
87+ sendCount := make ([]uint64 , streams )
88+
89+ stop := make (chan struct {})
90+
91+ // Producers: each stream pushes packets
92+ for sid := 0 ; sid < streams ; sid ++ {
93+ sid := sid
94+ wg .Add (1 )
95+ go func () {
96+ defer wg .Done ()
97+ seq := uint32 (0 )
98+ for {
99+ select {
100+ case <- stop :
101+ return
102+ default :
103+ }
104+ sq .Push (writeRequest {
105+ frame : Frame {sid : uint32 (sid )},
106+ seq : seq ,
107+ })
108+ seq ++
109+ time .Sleep (time .Duration (rand .Intn (300 )) * time .Microsecond )
110+ }
111+ }()
112+ }
113+
114+ // Consumer: slow network, 1 pop every 10ms
115+ wg .Add (1 )
116+ go func () {
117+ defer wg .Done ()
118+ ticker := time .NewTicker (10 * time .Millisecond )
119+ for {
120+ select {
121+ case <- stop :
122+ return
123+ case <- ticker .C :
124+ req , ok := sq .Pop ()
125+ if ok {
126+ sendCount [req .frame .sid ]++
127+ }
128+ }
129+ }
130+ }()
131+
132+ // ---- NEW: periodic live report ----
133+ go func () {
134+ ticker := time .NewTicker (500 * time .Millisecond )
135+ for {
136+ select {
137+ case <- stop :
138+ return
139+ case <- ticker .C :
140+ fmt .Printf ("[DEBUG] Current counts: %v\n " , sendCount )
141+ }
142+ }
143+ }()
144+
145+ // run test
146+ time .Sleep (testDuration )
147+ close (stop )
148+ wg .Wait ()
149+
150+ // ---- final report ----
151+ fmt .Println ("=== FINAL COUNTS ===" )
152+ fmt .Println (sendCount )
153+
154+ // ---- fairness check ----
155+ total := uint64 (0 )
156+ for _ , c := range sendCount {
157+ total += c
158+ }
159+ avg := total / streams
160+ tolerance := avg / 4 // 25%
161+
162+ for sid , c := range sendCount {
163+ if c < avg - tolerance || c > avg + tolerance {
164+ t .Errorf ("stream %d unfair: got %d, avg %d" , sid , c , avg )
165+ }
166+ }
167+ }
168+
169+ func TestShaperQueue_FastWriteSlowRead (t * testing.T ) {
170+ rand .Seed (time .Now ().UnixNano ())
171+
172+ const (
173+ streams = 10
174+ duration = 10 * time .Second
175+ producerWait = 1 * time .Microsecond // super fast writing
176+ consumerWait = 15 * time .Millisecond // super slow reading
177+ )
178+
179+ sq := NewShaperQueue ()
180+
181+ sendCount := make ([]uint64 , streams )
182+ stop := make (chan struct {})
183+ var wg sync.WaitGroup
184+
185+ // Producers: extremely fast writers
186+ for sid := 0 ; sid < streams ; sid ++ {
187+ sid := sid
188+ wg .Add (1 )
189+ go func () {
190+ defer wg .Done ()
191+ seq := uint32 (0 )
192+ for {
193+ select {
194+ case <- stop :
195+ return
196+ default :
197+ }
198+
199+ sq .Push (writeRequest {
200+ frame : Frame {sid : uint32 (sid )},
201+ seq : seq ,
202+ })
203+ seq ++
204+ time .Sleep (producerWait )
205+ }
206+ }()
207+ }
208+
209+ // Consumer: very slow reader
210+ wg .Add (1 )
211+ go func () {
212+ defer wg .Done ()
213+ for {
214+ select {
215+ case <- stop :
216+ return
217+ default :
218+ }
219+
220+ req , ok := sq .Pop ()
221+ if ok {
222+ sendCount [req .frame .sid ]++
223+ }
224+
225+ time .Sleep (consumerWait )
226+ }
227+ }()
228+
229+ // Periodic monitor
230+ go func () {
231+ ticker := time .NewTicker (500 * time .Millisecond )
232+ for {
233+ select {
234+ case <- stop :
235+ return
236+ case <- ticker .C :
237+ fmt .Printf ("[DEBUG] Queue size=%d, counts=%v\n " , sq .count , sendCount )
238+ }
239+ }
240+ }()
241+
242+ // Run test
243+ time .Sleep (duration )
244+ close (stop )
245+ wg .Wait ()
246+
247+ fmt .Printf ("=== FINAL ===\n counts=%v\n queue remaining=%d\n " , sendCount , sq .count )
248+
249+ // Check fairness
250+ total := uint64 (0 )
251+ for _ , v := range sendCount {
252+ total += v
253+ }
254+ avg := total / streams
255+ tolerance := avg / 3 // allow 33%
256+
257+ for sid , c := range sendCount {
258+ if c < avg - tolerance || c > avg + tolerance {
259+ t .Errorf ("stream %d unfair: got %d, avg %d" , sid , c , avg )
260+ }
261+ }
262+ }
0 commit comments