github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/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  }