The reconcile package is used for DOM reconcilation in Isomorphic Go web applications.

writesched_priority_test.go 17KB

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