gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/net/http2/writesched_priority_test.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package http2 6 7 import ( 8 "bytes" 9 "fmt" 10 "sort" 11 "testing" 12 ) 13 14 func defaultPriorityWriteScheduler() *priorityWriteScheduler { 15 return NewPriorityWriteScheduler(nil).(*priorityWriteScheduler) 16 } 17 18 func checkPriorityWellFormed(ws *priorityWriteScheduler) error { 19 for id, n := range ws.nodes { 20 if id != n.id { 21 return fmt.Errorf("bad ws.nodes: ws.nodes[%d] = %d", id, n.id) 22 } 23 if n.parent == nil { 24 if n.next != nil || n.prev != nil { 25 return fmt.Errorf("bad node %d: nil parent but prev/next not nil", id) 26 } 27 continue 28 } 29 found := false 30 for k := n.parent.kids; k != nil; k = k.next { 31 if k.id == id { 32 found = true 33 break 34 } 35 } 36 if !found { 37 return fmt.Errorf("bad node %d: not found in parent %d kids list", id, n.parent.id) 38 } 39 } 40 return nil 41 } 42 43 func fmtTree(ws *priorityWriteScheduler, fmtNode func(*priorityNode) string) string { 44 var ids []int 45 for _, n := range ws.nodes { 46 ids = append(ids, int(n.id)) 47 } 48 sort.Ints(ids) 49 50 var buf bytes.Buffer 51 for _, id := range ids { 52 if buf.Len() != 0 { 53 buf.WriteString(" ") 54 } 55 if id == 0 { 56 buf.WriteString(fmtNode(&ws.root)) 57 } else { 58 buf.WriteString(fmtNode(ws.nodes[uint32(id)])) 59 } 60 } 61 return buf.String() 62 } 63 64 func fmtNodeParentSkipRoot(n *priorityNode) string { 65 switch { 66 case n.id == 0: 67 return "" 68 case n.parent == nil: 69 return fmt.Sprintf("%d{parent:nil}", n.id) 70 default: 71 return fmt.Sprintf("%d{parent:%d}", n.id, n.parent.id) 72 } 73 } 74 75 func fmtNodeWeightParentSkipRoot(n *priorityNode) string { 76 switch { 77 case n.id == 0: 78 return "" 79 case n.parent == nil: 80 return fmt.Sprintf("%d{weight:%d,parent:nil}", n.id, n.weight) 81 default: 82 return fmt.Sprintf("%d{weight:%d,parent:%d}", n.id, n.weight, n.parent.id) 83 } 84 } 85 86 func TestPriorityTwoStreams(t *testing.T) { 87 ws := defaultPriorityWriteScheduler() 88 ws.OpenStream(1, OpenStreamOptions{}) 89 ws.OpenStream(2, OpenStreamOptions{}) 90 91 want := "1{weight:15,parent:0} 2{weight:15,parent:0}" 92 if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { 93 t.Errorf("After open\ngot %q\nwant %q", got, want) 94 } 95 96 // Move 1's parent to 2. 97 ws.AdjustStream(1, PriorityParam{ 98 StreamDep: 2, 99 Weight: 32, 100 Exclusive: false, 101 }) 102 want = "1{weight:32,parent:2} 2{weight:15,parent:0}" 103 if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { 104 t.Errorf("After adjust\ngot %q\nwant %q", got, want) 105 } 106 107 if err := checkPriorityWellFormed(ws); err != nil { 108 t.Error(err) 109 } 110 } 111 112 func TestPriorityAdjustExclusiveZero(t *testing.T) { 113 // 1, 2, and 3 are all children of the 0 stream. 114 // Exclusive reprioritization to any of the streams should bring 115 // the rest of the streams under the reprioritized stream. 116 ws := defaultPriorityWriteScheduler() 117 ws.OpenStream(1, OpenStreamOptions{}) 118 ws.OpenStream(2, OpenStreamOptions{}) 119 ws.OpenStream(3, OpenStreamOptions{}) 120 121 want := "1{weight:15,parent:0} 2{weight:15,parent:0} 3{weight:15,parent:0}" 122 if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { 123 t.Errorf("After open\ngot %q\nwant %q", got, want) 124 } 125 126 ws.AdjustStream(2, PriorityParam{ 127 StreamDep: 0, 128 Weight: 20, 129 Exclusive: true, 130 }) 131 want = "1{weight:15,parent:2} 2{weight:20,parent:0} 3{weight:15,parent:2}" 132 if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { 133 t.Errorf("After adjust\ngot %q\nwant %q", got, want) 134 } 135 136 if err := checkPriorityWellFormed(ws); err != nil { 137 t.Error(err) 138 } 139 } 140 141 func TestPriorityAdjustOwnParent(t *testing.T) { 142 // Assigning a node as its own parent should have no effect. 143 ws := defaultPriorityWriteScheduler() 144 ws.OpenStream(1, OpenStreamOptions{}) 145 ws.OpenStream(2, OpenStreamOptions{}) 146 ws.AdjustStream(2, PriorityParam{ 147 StreamDep: 2, 148 Weight: 20, 149 Exclusive: true, 150 }) 151 want := "1{weight:15,parent:0} 2{weight:15,parent:0}" 152 if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { 153 t.Errorf("After adjust\ngot %q\nwant %q", got, want) 154 } 155 if err := checkPriorityWellFormed(ws); err != nil { 156 t.Error(err) 157 } 158 } 159 160 func TestPriorityClosedStreams(t *testing.T) { 161 ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{MaxClosedNodesInTree: 2}).(*priorityWriteScheduler) 162 ws.OpenStream(1, OpenStreamOptions{}) 163 ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) 164 ws.OpenStream(3, OpenStreamOptions{PusherID: 2}) 165 ws.OpenStream(4, OpenStreamOptions{PusherID: 3}) 166 167 // Close the first three streams. We lose 1, but keep 2 and 3. 168 ws.CloseStream(1) 169 ws.CloseStream(2) 170 ws.CloseStream(3) 171 172 want := "2{weight:15,parent:0} 3{weight:15,parent:2} 4{weight:15,parent:3}" 173 if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { 174 t.Errorf("After close\ngot %q\nwant %q", got, want) 175 } 176 if err := checkPriorityWellFormed(ws); err != nil { 177 t.Error(err) 178 } 179 180 // Adding a stream as an exclusive child of 1 gives it default 181 // priorities, since 1 is gone. 182 ws.OpenStream(5, OpenStreamOptions{}) 183 ws.AdjustStream(5, PriorityParam{StreamDep: 1, Weight: 15, Exclusive: true}) 184 185 // Adding a stream as an exclusive child of 2 should work, since 2 is not gone. 186 ws.OpenStream(6, OpenStreamOptions{}) 187 ws.AdjustStream(6, PriorityParam{StreamDep: 2, Weight: 15, Exclusive: true}) 188 189 want = "2{weight:15,parent:0} 3{weight:15,parent:6} 4{weight:15,parent:3} 5{weight:15,parent:0} 6{weight:15,parent:2}" 190 if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { 191 t.Errorf("After add streams\ngot %q\nwant %q", got, want) 192 } 193 if err := checkPriorityWellFormed(ws); err != nil { 194 t.Error(err) 195 } 196 } 197 198 func TestPriorityClosedStreamsDisabled(t *testing.T) { 199 ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{}).(*priorityWriteScheduler) 200 ws.OpenStream(1, OpenStreamOptions{}) 201 ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) 202 ws.OpenStream(3, OpenStreamOptions{PusherID: 2}) 203 204 // Close the first two streams. We keep only 3. 205 ws.CloseStream(1) 206 ws.CloseStream(2) 207 208 want := "3{weight:15,parent:0}" 209 if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { 210 t.Errorf("After close\ngot %q\nwant %q", got, want) 211 } 212 if err := checkPriorityWellFormed(ws); err != nil { 213 t.Error(err) 214 } 215 } 216 217 func TestPriorityIdleStreams(t *testing.T) { 218 ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{MaxIdleNodesInTree: 2}).(*priorityWriteScheduler) 219 ws.AdjustStream(1, PriorityParam{StreamDep: 0, Weight: 15}) // idle 220 ws.AdjustStream(2, PriorityParam{StreamDep: 0, Weight: 15}) // idle 221 ws.AdjustStream(3, PriorityParam{StreamDep: 2, Weight: 20}) // idle 222 ws.OpenStream(4, OpenStreamOptions{}) 223 ws.OpenStream(5, OpenStreamOptions{}) 224 ws.OpenStream(6, OpenStreamOptions{}) 225 ws.AdjustStream(4, PriorityParam{StreamDep: 1, Weight: 15}) 226 ws.AdjustStream(5, PriorityParam{StreamDep: 2, Weight: 15}) 227 ws.AdjustStream(6, PriorityParam{StreamDep: 3, Weight: 15}) 228 229 want := "2{weight:15,parent:0} 3{weight:20,parent:2} 4{weight:15,parent:0} 5{weight:15,parent:2} 6{weight:15,parent:3}" 230 if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { 231 t.Errorf("After open\ngot %q\nwant %q", got, want) 232 } 233 if err := checkPriorityWellFormed(ws); err != nil { 234 t.Error(err) 235 } 236 } 237 238 func TestPriorityIdleStreamsDisabled(t *testing.T) { 239 ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{}).(*priorityWriteScheduler) 240 ws.AdjustStream(1, PriorityParam{StreamDep: 0, Weight: 15}) // idle 241 ws.AdjustStream(2, PriorityParam{StreamDep: 0, Weight: 15}) // idle 242 ws.AdjustStream(3, PriorityParam{StreamDep: 2, Weight: 20}) // idle 243 ws.OpenStream(4, OpenStreamOptions{}) 244 245 want := "4{weight:15,parent:0}" 246 if got := fmtTree(ws, fmtNodeWeightParentSkipRoot); got != want { 247 t.Errorf("After open\ngot %q\nwant %q", got, want) 248 } 249 if err := checkPriorityWellFormed(ws); err != nil { 250 t.Error(err) 251 } 252 } 253 254 func TestPrioritySection531NonExclusive(t *testing.T) { 255 // Example from RFC 7540 Section 5.3.1. 256 // A,B,C,D = 1,2,3,4 257 ws := defaultPriorityWriteScheduler() 258 ws.OpenStream(1, OpenStreamOptions{}) 259 ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) 260 ws.OpenStream(3, OpenStreamOptions{PusherID: 1}) 261 ws.OpenStream(4, OpenStreamOptions{}) 262 ws.AdjustStream(4, PriorityParam{ 263 StreamDep: 1, 264 Weight: 15, 265 Exclusive: false, 266 }) 267 want := "1{parent:0} 2{parent:1} 3{parent:1} 4{parent:1}" 268 if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want { 269 t.Errorf("After adjust\ngot %q\nwant %q", got, want) 270 } 271 if err := checkPriorityWellFormed(ws); err != nil { 272 t.Error(err) 273 } 274 } 275 276 func TestPrioritySection531Exclusive(t *testing.T) { 277 // Example from RFC 7540 Section 5.3.1. 278 // A,B,C,D = 1,2,3,4 279 ws := defaultPriorityWriteScheduler() 280 ws.OpenStream(1, OpenStreamOptions{}) 281 ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) 282 ws.OpenStream(3, OpenStreamOptions{PusherID: 1}) 283 ws.OpenStream(4, OpenStreamOptions{}) 284 ws.AdjustStream(4, PriorityParam{ 285 StreamDep: 1, 286 Weight: 15, 287 Exclusive: true, 288 }) 289 want := "1{parent:0} 2{parent:4} 3{parent:4} 4{parent:1}" 290 if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want { 291 t.Errorf("After adjust\ngot %q\nwant %q", got, want) 292 } 293 if err := checkPriorityWellFormed(ws); err != nil { 294 t.Error(err) 295 } 296 } 297 298 func makeSection533Tree() *priorityWriteScheduler { 299 // Initial tree from RFC 7540 Section 5.3.3. 300 // A,B,C,D,E,F = 1,2,3,4,5,6 301 ws := defaultPriorityWriteScheduler() 302 ws.OpenStream(1, OpenStreamOptions{}) 303 ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) 304 ws.OpenStream(3, OpenStreamOptions{PusherID: 1}) 305 ws.OpenStream(4, OpenStreamOptions{PusherID: 3}) 306 ws.OpenStream(5, OpenStreamOptions{PusherID: 3}) 307 ws.OpenStream(6, OpenStreamOptions{PusherID: 4}) 308 return ws 309 } 310 311 func TestPrioritySection533NonExclusive(t *testing.T) { 312 // Example from RFC 7540 Section 5.3.3. 313 // A,B,C,D,E,F = 1,2,3,4,5,6 314 ws := defaultPriorityWriteScheduler() 315 ws.OpenStream(1, OpenStreamOptions{}) 316 ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) 317 ws.OpenStream(3, OpenStreamOptions{PusherID: 1}) 318 ws.OpenStream(4, OpenStreamOptions{PusherID: 3}) 319 ws.OpenStream(5, OpenStreamOptions{PusherID: 3}) 320 ws.OpenStream(6, OpenStreamOptions{PusherID: 4}) 321 ws.AdjustStream(1, PriorityParam{ 322 StreamDep: 4, 323 Weight: 15, 324 Exclusive: false, 325 }) 326 want := "1{parent:4} 2{parent:1} 3{parent:1} 4{parent:0} 5{parent:3} 6{parent:4}" 327 if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want { 328 t.Errorf("After adjust\ngot %q\nwant %q", got, want) 329 } 330 if err := checkPriorityWellFormed(ws); err != nil { 331 t.Error(err) 332 } 333 } 334 335 func TestPrioritySection533Exclusive(t *testing.T) { 336 // Example from RFC 7540 Section 5.3.3. 337 // A,B,C,D,E,F = 1,2,3,4,5,6 338 ws := defaultPriorityWriteScheduler() 339 ws.OpenStream(1, OpenStreamOptions{}) 340 ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) 341 ws.OpenStream(3, OpenStreamOptions{PusherID: 1}) 342 ws.OpenStream(4, OpenStreamOptions{PusherID: 3}) 343 ws.OpenStream(5, OpenStreamOptions{PusherID: 3}) 344 ws.OpenStream(6, OpenStreamOptions{PusherID: 4}) 345 ws.AdjustStream(1, PriorityParam{ 346 StreamDep: 4, 347 Weight: 15, 348 Exclusive: true, 349 }) 350 want := "1{parent:4} 2{parent:1} 3{parent:1} 4{parent:0} 5{parent:3} 6{parent:1}" 351 if got := fmtTree(ws, fmtNodeParentSkipRoot); got != want { 352 t.Errorf("After adjust\ngot %q\nwant %q", got, want) 353 } 354 if err := checkPriorityWellFormed(ws); err != nil { 355 t.Error(err) 356 } 357 } 358 359 func checkPopAll(ws WriteScheduler, order []uint32) error { 360 for k, id := range order { 361 wr, ok := ws.Pop() 362 if !ok { 363 return fmt.Errorf("Pop[%d]: got ok=false, want %d (order=%v)", k, id, order) 364 } 365 if got := wr.StreamID(); got != id { 366 return fmt.Errorf("Pop[%d]: got %v, want %d (order=%v)", k, got, id, order) 367 } 368 } 369 wr, ok := ws.Pop() 370 if ok { 371 return fmt.Errorf("Pop[%d]: got %v, want ok=false (order=%v)", len(order), wr.StreamID(), order) 372 } 373 return nil 374 } 375 376 func TestPriorityPopFrom533Tree(t *testing.T) { 377 ws := makeSection533Tree() 378 379 ws.Push(makeWriteHeadersRequest(3 /*C*/)) 380 ws.Push(makeWriteNonStreamRequest()) 381 ws.Push(makeWriteHeadersRequest(5 /*E*/)) 382 ws.Push(makeWriteHeadersRequest(1 /*A*/)) 383 t.Log("tree:", fmtTree(ws, fmtNodeParentSkipRoot)) 384 385 if err := checkPopAll(ws, []uint32{0 /*NonStream*/, 1, 3, 5}); err != nil { 386 t.Error(err) 387 } 388 } 389 390 func TestPriorityPopFromLinearTree(t *testing.T) { 391 ws := defaultPriorityWriteScheduler() 392 ws.OpenStream(1, OpenStreamOptions{}) 393 ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) 394 ws.OpenStream(3, OpenStreamOptions{PusherID: 2}) 395 ws.OpenStream(4, OpenStreamOptions{PusherID: 3}) 396 397 ws.Push(makeWriteHeadersRequest(3)) 398 ws.Push(makeWriteHeadersRequest(4)) 399 ws.Push(makeWriteHeadersRequest(1)) 400 ws.Push(makeWriteHeadersRequest(2)) 401 ws.Push(makeWriteNonStreamRequest()) 402 ws.Push(makeWriteNonStreamRequest()) 403 t.Log("tree:", fmtTree(ws, fmtNodeParentSkipRoot)) 404 405 if err := checkPopAll(ws, []uint32{0, 0 /*NonStreams*/, 1, 2, 3, 4}); err != nil { 406 t.Error(err) 407 } 408 } 409 410 func TestPriorityFlowControl(t *testing.T) { 411 ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{ThrottleOutOfOrderWrites: false}) 412 ws.OpenStream(1, OpenStreamOptions{}) 413 ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) 414 415 sc := &serverConn{maxFrameSize: 16} 416 st1 := &stream{id: 1, sc: sc} 417 st2 := &stream{id: 2, sc: sc} 418 419 ws.Push(FrameWriteRequest{&writeData{1, make([]byte, 16), false}, st1, nil}) 420 ws.Push(FrameWriteRequest{&writeData{2, make([]byte, 16), false}, st2, nil}) 421 ws.AdjustStream(2, PriorityParam{StreamDep: 1}) 422 423 // No flow-control bytes available. 424 if wr, ok := ws.Pop(); ok { 425 t.Fatalf("Pop(limited by flow control)=%v,true, want false", wr) 426 } 427 428 // Add enough flow-control bytes to write st2 in two Pop calls. 429 // Should write data from st2 even though it's lower priority than st1. 430 for i := 1; i <= 2; i++ { 431 st2.flow.add(8) 432 wr, ok := ws.Pop() 433 if !ok { 434 t.Fatalf("Pop(%d)=false, want true", i) 435 } 436 if got, want := wr.DataSize(), 8; got != want { 437 t.Fatalf("Pop(%d)=%d bytes, want %d bytes", i, got, want) 438 } 439 } 440 } 441 442 func TestPriorityThrottleOutOfOrderWrites(t *testing.T) { 443 ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{ThrottleOutOfOrderWrites: true}) 444 ws.OpenStream(1, OpenStreamOptions{}) 445 ws.OpenStream(2, OpenStreamOptions{PusherID: 1}) 446 447 sc := &serverConn{maxFrameSize: 4096} 448 st1 := &stream{id: 1, sc: sc} 449 st2 := &stream{id: 2, sc: sc} 450 st1.flow.add(4096) 451 st2.flow.add(4096) 452 ws.Push(FrameWriteRequest{&writeData{2, make([]byte, 4096), false}, st2, nil}) 453 ws.AdjustStream(2, PriorityParam{StreamDep: 1}) 454 455 // We have enough flow-control bytes to write st2 in a single Pop call. 456 // However, due to out-of-order write throttling, the first call should 457 // only write 1KB. 458 wr, ok := ws.Pop() 459 if !ok { 460 t.Fatalf("Pop(st2.first)=false, want true") 461 } 462 if got, want := wr.StreamID(), uint32(2); got != want { 463 t.Fatalf("Pop(st2.first)=stream %d, want stream %d", got, want) 464 } 465 if got, want := wr.DataSize(), 1024; got != want { 466 t.Fatalf("Pop(st2.first)=%d bytes, want %d bytes", got, want) 467 } 468 469 // Now add data on st1. This should take precedence. 470 ws.Push(FrameWriteRequest{&writeData{1, make([]byte, 4096), false}, st1, nil}) 471 wr, ok = ws.Pop() 472 if !ok { 473 t.Fatalf("Pop(st1)=false, want true") 474 } 475 if got, want := wr.StreamID(), uint32(1); got != want { 476 t.Fatalf("Pop(st1)=stream %d, want stream %d", got, want) 477 } 478 if got, want := wr.DataSize(), 4096; got != want { 479 t.Fatalf("Pop(st1)=%d bytes, want %d bytes", got, want) 480 } 481 482 // Should go back to writing 1KB from st2. 483 wr, ok = ws.Pop() 484 if !ok { 485 t.Fatalf("Pop(st2.last)=false, want true") 486 } 487 if got, want := wr.StreamID(), uint32(2); got != want { 488 t.Fatalf("Pop(st2.last)=stream %d, want stream %d", got, want) 489 } 490 if got, want := wr.DataSize(), 1024; got != want { 491 t.Fatalf("Pop(st2.last)=%d bytes, want %d bytes", got, want) 492 } 493 } 494 495 func TestPriorityWeights(t *testing.T) { 496 ws := defaultPriorityWriteScheduler() 497 ws.OpenStream(1, OpenStreamOptions{}) 498 ws.OpenStream(2, OpenStreamOptions{}) 499 500 sc := &serverConn{maxFrameSize: 8} 501 st1 := &stream{id: 1, sc: sc} 502 st2 := &stream{id: 2, sc: sc} 503 st1.flow.add(40) 504 st2.flow.add(40) 505 506 ws.Push(FrameWriteRequest{&writeData{1, make([]byte, 40), false}, st1, nil}) 507 ws.Push(FrameWriteRequest{&writeData{2, make([]byte, 40), false}, st2, nil}) 508 ws.AdjustStream(1, PriorityParam{StreamDep: 0, Weight: 34}) 509 ws.AdjustStream(2, PriorityParam{StreamDep: 0, Weight: 9}) 510 511 // st1 gets 3.5x the bandwidth of st2 (3.5 = (34+1)/(9+1)). 512 // The maximum frame size is 8 bytes. The write sequence should be: 513 // st1, total bytes so far is (st1=8, st=0) 514 // st2, total bytes so far is (st1=8, st=8) 515 // st1, total bytes so far is (st1=16, st=8) 516 // st1, total bytes so far is (st1=24, st=8) // 3x bandwidth 517 // st1, total bytes so far is (st1=32, st=8) // 4x bandwidth 518 // st2, total bytes so far is (st1=32, st=16) // 2x bandwidth 519 // st1, total bytes so far is (st1=40, st=16) 520 // st2, total bytes so far is (st1=40, st=24) 521 // st2, total bytes so far is (st1=40, st=32) 522 // st2, total bytes so far is (st1=40, st=40) 523 if err := checkPopAll(ws, []uint32{1, 2, 1, 1, 1, 2, 1, 2, 2, 2}); err != nil { 524 t.Error(err) 525 } 526 } 527 528 func TestPriorityRstStreamOnNonOpenStreams(t *testing.T) { 529 ws := NewPriorityWriteScheduler(&PriorityWriteSchedulerConfig{ 530 MaxClosedNodesInTree: 0, 531 MaxIdleNodesInTree: 0, 532 }) 533 ws.OpenStream(1, OpenStreamOptions{}) 534 ws.CloseStream(1) 535 ws.Push(FrameWriteRequest{write: streamError(1, ErrCodeProtocol)}) 536 ws.Push(FrameWriteRequest{write: streamError(2, ErrCodeProtocol)}) 537 538 if err := checkPopAll(ws, []uint32{1, 2}); err != nil { 539 t.Error(err) 540 } 541 }