package runtime import ( "errors" "testing" "time" ) func TestSessionMachineBackoffAndStableReset_HP_FLOW_01(t *testing.T) { t.Parallel() machine, err := NewSessionMachine(BackoffOptions{Initial: time.Second, Maximum: 8 * time.Second, StableReset: 60 * time.Second}, func(cap time.Duration) time.Duration { return cap / 2 }) if err != nil { t.Fatal(err) } if err := machine.StartConnecting(0); err != nil { t.Fatal(err) } if delay := machine.Failed(0); delay != 500*time.Millisecond || machine.NextConnectAt() != delay { t.Fatalf("first failure delay/next = %s/%s", delay, machine.NextConnectAt()) } if err := machine.StartConnecting(499 * time.Millisecond); !errors.Is(err, ErrInvalidTransition) { t.Fatalf("early reconnect error = %v, want ErrInvalidTransition", err) } if err := machine.StartConnecting(500 * time.Millisecond); err != nil { t.Fatal(err) } if delay := machine.Failed(500 * time.Millisecond); delay != time.Second { t.Fatalf("second failure delay = %s, want 1s", delay) } if err := machine.StartConnecting(1500 * time.Millisecond); err != nil { t.Fatal(err) } if err := machine.TransportConnected(); err != nil { t.Fatal(err) } if err := machine.Welcomed(); err != nil { t.Fatal(err) } if err := machine.Reconciled(2 * time.Second); err != nil { t.Fatal(err) } if delay := machine.Failed(62 * time.Second); delay != 500*time.Millisecond { t.Fatalf("stable session did not reset backoff: %s", delay) } } func TestSendQueuePriorityReserveAndFairness_HP_FLOW_02(t *testing.T) { t.Parallel() queue, err := NewSendQueue(QueueOptions{MaxBytes: 100, ControlReserveBytes: 20, EssentialReserveBytes: 30, ControlBurst: 2}) if err != nil { t.Fatal(err) } if err := queue.Enqueue(Frame{Priority: PriorityData, Payload: make([]byte, 50)}); err != nil { t.Fatal(err) } if err := queue.Enqueue(Frame{Priority: PriorityData, Payload: []byte("x")}); !errors.Is(err, ErrSendQueueFull) { t.Fatalf("data consumed reserved bytes: %v", err) } if err := queue.Enqueue(Frame{Priority: PriorityEssential, Payload: make([]byte, 30)}); err != nil { t.Fatal(err) } if err := queue.Enqueue(Frame{Priority: PriorityControl, Payload: make([]byte, 10)}); err != nil { t.Fatal(err) } if err := queue.Enqueue(Frame{Priority: PriorityControl, Payload: make([]byte, 10)}); err != nil { t.Fatal(err) } if got := queue.Bytes(); got != 100 { t.Fatalf("queue bytes = %d, want 100", got) } for want := 0; want < 2; want++ { frame, ok := queue.Next() if !ok || frame.Priority != PriorityControl { t.Fatalf("control frame %d = %#v, %t", want, frame, ok) } if want == 0 { if err := queue.Enqueue(Frame{Priority: PriorityControl, Payload: []byte("c")}); err != nil { t.Fatal(err) } } } frame, ok := queue.Next() if !ok || frame.Priority != PriorityEssential { t.Fatalf("essential frame starved by controls: %#v, %t", frame, ok) } frame, ok = queue.Next() if !ok || frame.Priority != PriorityControl { t.Fatalf("remaining control frame = %#v, %t", frame, ok) } frame, ok = queue.Next() if !ok || frame.Priority != PriorityData || queue.Bytes() != 0 { t.Fatalf("data frame/final bytes = %#v, %t/%d", frame, ok, queue.Bytes()) } }