refactor(handler/http2): split handler into 3 focused files with 52 tests
Extract authenticate/probe-resistance to auth.go and roundTrip/forwarding to proxy.go, following the handler/http/ pattern. Export sentinel errors (ErrAuthFailed, ErrWrongConnType) for precise test assertions. Fix flushWriter panic recovery to handle non-string/non-error panics. Default HTTPS port to 443 when no port is specified in the Host header.
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
package http2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testFlusher struct {
|
||||
bytes.Buffer
|
||||
flushed bool
|
||||
}
|
||||
|
||||
func (f *testFlusher) Flush() {
|
||||
f.flushed = true
|
||||
}
|
||||
|
||||
func TestFlushWriter_Write(t *testing.T) {
|
||||
t.Run("normal write", func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
fw := flushWriter{w: &buf}
|
||||
n, err := fw.Write([]byte("hello"))
|
||||
if err != nil {
|
||||
t.Fatalf("Write: %v", err)
|
||||
}
|
||||
if n != 5 {
|
||||
t.Errorf("n = %d, want 5", n)
|
||||
}
|
||||
if buf.String() != "hello" {
|
||||
t.Errorf("buf = %q, want %q", buf.String(), "hello")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("write and flush", func(t *testing.T) {
|
||||
tf := &testFlusher{}
|
||||
fw := flushWriter{w: tf}
|
||||
_, err := fw.Write([]byte("hello"))
|
||||
if err != nil {
|
||||
t.Fatalf("Write: %v", err)
|
||||
}
|
||||
if !tf.flushed {
|
||||
t.Error("expected flush after write")
|
||||
}
|
||||
if tf.String() != "hello" {
|
||||
t.Errorf("buf = %q, want %q", tf.String(), "hello")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestFlushWriter_PanicRecovery(t *testing.T) {
|
||||
t.Run("string panic", func(t *testing.T) {
|
||||
pw := &panicWriter{panicVal: "boom"}
|
||||
fw := flushWriter{w: pw}
|
||||
_, err := fw.Write([]byte("data"))
|
||||
if err == nil {
|
||||
t.Fatal("expected error from panic recovery")
|
||||
}
|
||||
if err.Error() != "boom" {
|
||||
t.Errorf("err = %q, want %q", err.Error(), "boom")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("error panic", func(t *testing.T) {
|
||||
pw := &panicWriter{panicVal: errors.New("err boom")}
|
||||
fw := flushWriter{w: pw}
|
||||
_, err := fw.Write([]byte("data"))
|
||||
if err == nil {
|
||||
t.Fatal("expected error from panic recovery")
|
||||
}
|
||||
if err.Error() != "err boom" {
|
||||
t.Errorf("err = %q, want %q", err.Error(), "err boom")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("int panic", func(t *testing.T) {
|
||||
pw := &panicWriter{panicVal: 42}
|
||||
fw := flushWriter{w: pw}
|
||||
_, err := fw.Write([]byte("data"))
|
||||
if err == nil {
|
||||
t.Fatal("expected error from panic recovery")
|
||||
}
|
||||
if err.Error() != "42" {
|
||||
t.Errorf("err = %q, want %q", err.Error(), "42")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type panicWriter struct {
|
||||
panicVal any
|
||||
}
|
||||
|
||||
func (w *panicWriter) Write([]byte) (int, error) {
|
||||
panic(w.panicVal)
|
||||
}
|
||||
|
||||
func TestFlushWriter_ImplementsHTTPFlusher(t *testing.T) {
|
||||
// flushWriter should allow the wrapped value to be used as http.Flusher.
|
||||
tf := &testFlusher{}
|
||||
fw := flushWriter{w: tf}
|
||||
_, err := fw.Write([]byte("x"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !tf.flushed {
|
||||
t.Error("expected Flush() to be called after Write()")
|
||||
}
|
||||
// Verify that testFlusher is recognized as http.Flusher.
|
||||
var _ http.Flusher = tf
|
||||
}
|
||||
Reference in New Issue
Block a user