107 lines
3.6 KiB
Go
107 lines
3.6 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"proxy-pool/internal/domain/routing"
|
|
"proxy-pool/internal/gateway/snapshot"
|
|
)
|
|
|
|
func TestRulesRouterReturnsMatchedUpstreams(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rules, err := routing.Compile([]routing.Rule{{
|
|
Name: "api",
|
|
Match: routing.Match{HostRegex: `^example\.test$`, Methods: []string{http.MethodGet}, PathRegex: `^/v1/`},
|
|
Upstreams: []string{"provider-a", "provider-b"},
|
|
Action: routing.ActionProxy,
|
|
}})
|
|
if err != nil {
|
|
t.Fatalf("routing.Compile() error = %v", err)
|
|
}
|
|
router := NewRulesRouter(rules)
|
|
request := httptest.NewRequest(http.MethodGet, "http://example.test/v1/items", nil)
|
|
|
|
result, err := router.Route(request)
|
|
if err != nil {
|
|
t.Fatalf("Route() error = %v", err)
|
|
}
|
|
if !reflect.DeepEqual(result.Upstreams, []string{"provider-a", "provider-b"}) {
|
|
t.Fatalf("upstreams = %v", result.Upstreams)
|
|
}
|
|
}
|
|
|
|
func TestRulesRouterReturnsStaticDirectRoute(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rules, err := routing.Compile([]routing.Rule{{
|
|
Name: "direct-api", Match: routing.Match{HostRegex: "^api\\.example\\.test$"},
|
|
Action: routing.ActionDirect,
|
|
}})
|
|
if err != nil {
|
|
t.Fatalf("routing.Compile() error = %v", err)
|
|
}
|
|
result, err := NewRulesRouter(rules).Route(httptest.NewRequest(http.MethodGet, "http://api.example.test/v1/items", nil))
|
|
if err != nil {
|
|
t.Fatalf("Route() error = %v", err)
|
|
}
|
|
if result.RoutingName != "direct-api" || result.Action != routing.ActionDirect || len(result.Upstreams) != 0 {
|
|
t.Fatalf("Route() = %+v", result)
|
|
}
|
|
}
|
|
|
|
func TestRulesRouterRejectsExplicitRejectAndMissingRoute(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rules, err := routing.Compile([]routing.Rule{{
|
|
Name: "blocked",
|
|
Match: routing.Match{HostRegex: `^blocked\.test$`},
|
|
Action: routing.ActionReject,
|
|
}})
|
|
if err != nil {
|
|
t.Fatalf("routing.Compile() error = %v", err)
|
|
}
|
|
router := NewRulesRouter(rules)
|
|
|
|
if _, err := router.Route(httptest.NewRequest(http.MethodGet, "http://blocked.test/", nil)); !errors.Is(err, ErrRouteRejected) {
|
|
t.Fatalf("blocked Route() error = %v", err)
|
|
}
|
|
if _, err := router.Route(httptest.NewRequest(http.MethodGet, "http://missing.test/", nil)); !errors.Is(err, ErrRouteNotFound) {
|
|
t.Fatalf("missing Route() error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSnapshotRouterMatchesRulesFromCurrentSnapshot(t *testing.T) {
|
|
store := snapshot.NewStore("cluster-a", "worker-a")
|
|
envelope := snapshot.Envelope{
|
|
ClusterID: "cluster-a", WorkerID: "worker-a", Epoch: 1, Version: 1, Full: true,
|
|
ValidUntil: time.Now().Add(time.Minute),
|
|
Routing: []routing.Rule{{
|
|
Name: "gateway-api", Match: routing.Match{HostRegex: `^api\.example\.test$`},
|
|
Upstreams: []string{"provider-a"}, Action: routing.ActionProxy,
|
|
Strategy: routing.Strategy{Type: routing.StrategyWeighted, Weights: map[string]uint32{"provider-a": 3}},
|
|
OnUnavailable: routing.OnUnavailableWait, WaitTimeout: 25 * time.Millisecond,
|
|
}},
|
|
}
|
|
envelope.Checksum = snapshot.ChecksumWithRouting(envelope.Proxies, envelope.Routing)
|
|
if err := store.Apply(envelope); err != nil {
|
|
t.Fatalf("Apply(): %v", err)
|
|
}
|
|
router := NewSnapshotRouter(store)
|
|
|
|
result, err := router.Route(httptest.NewRequest(http.MethodGet, "http://api.example.test/items", nil))
|
|
if err != nil {
|
|
t.Fatalf("Route(): %v", err)
|
|
}
|
|
if result.RoutingName != "gateway-api" || result.Strategy.Type != routing.StrategyWeighted ||
|
|
!reflect.DeepEqual(result.Strategy.Weights, map[string]uint32{"provider-a": 3}) ||
|
|
result.OnUnavailable != routing.OnUnavailableWait || result.WaitTimeout != 25*time.Millisecond {
|
|
t.Fatalf("Route() = %+v", result)
|
|
}
|
|
}
|