lego/platform/tester/servermock/builder.go

84 lines
1.8 KiB
Go

package servermock
import (
"net/http"
"net/http/httptest"
"slices"
"testing"
"github.com/stretchr/testify/require"
)
// Link represents a middleware interface, enabling middleware chaining.
type Link interface {
Bind(next http.Handler) http.Handler
}
// LinkFunc defines a function type [Link].
type LinkFunc func(next http.Handler) http.Handler
func (f LinkFunc) Bind(next http.Handler) http.Handler {
return f(next)
}
// ClientBuilder defines a function type for creating a client of type T based on a httptest.Server instance.
type ClientBuilder[T any] func(server *httptest.Server) (T, error)
// Builder is a type that facilitates the construction of testable HTTP clients and server.
// It allows defining routes, attaching middleware, and creating custom HTTP clients.
type Builder[T any] struct {
mux *http.ServeMux
chain []Link
clientBuilder ClientBuilder[T]
}
func NewBuilder[T any](clientBuilder ClientBuilder[T], chain ...Link) *Builder[T] {
return &Builder[T]{
mux: http.NewServeMux(),
chain: chain,
clientBuilder: clientBuilder,
}
}
func (b *Builder[T]) Route(pattern string, handler http.Handler, chain ...Link) *Builder[T] {
if handler == nil {
handler = Noop()
}
for _, link := range slices.Backward(b.chain) {
handler = link.Bind(handler)
}
for _, link := range slices.Backward(chain) {
handler = link.Bind(handler)
}
b.mux.Handle(pattern, handler)
return b
}
func (b *Builder[T]) Build(t *testing.T) T {
t.Helper()
server := httptest.NewServer(b.mux)
t.Cleanup(server.Close)
client, err := b.clientBuilder(server)
require.NoError(t, err)
return client
}
func (b *Builder[T]) BuildHTTPS(t *testing.T) T {
t.Helper()
server := httptest.NewTLSServer(b.mux)
t.Cleanup(server.Close)
client, err := b.clientBuilder(server)
require.NoError(t, err)
return client
}