func TestStreaming(t *testing.T) { const expectedParts = 3 payload := []byte("some data to stream") s := startTestServer(payload, expectedParts, voidCheck) defer s.Close() doc := fmt.Sprintf(`hello: Path("/hello") -> "%s"`, s.URL) dc, err := testdataclient.NewDoc(doc) if err != nil { t.Error(err) } p := New(routing.New(routing.Options{ nil, routing.MatchingOptionsNone, sourcePollTimeout, []routing.DataClient{dc}, 0}), OptionsNone) delay() u, _ := url.ParseRequestURI("https://www.example.org/hello") r := &http.Request{ URL: u, Method: "GET"} w := httptest.NewRecorder() parts := 0 total := 0 done := make(chan int) go p.ServeHTTP(w, r) go func() { for { buf := w.Body.Bytes() if len(buf) == 0 { time.Sleep(streamingDelay) continue } parts++ total += len(buf) if total >= len(payload) { close(done) return } } }() select { case <-done: if parts <= expectedParts { t.Error("streaming failed", parts) } case <-time.After(150 * time.Millisecond): t.Error("streaming timeout") } }
func TestProcessesRequestWithShuntBackend(t *testing.T) { u, _ := url.ParseRequestURI("https://www.example.org/hello") r := &http.Request{ URL: u, Method: "GET", Header: http.Header{"X-Test-Header": []string{"test value"}}} w := httptest.NewRecorder() fr := make(filters.Registry) fr.Register(builtin.NewResponseHeader()) doc := `hello: Path("/hello") -> responseHeader("X-Test-Response-Header", "response header value") -> <shunt>` dc, err := testdataclient.NewDoc(doc) if err != nil { t.Error(err) } p := New(routing.New(routing.Options{ fr, routing.MatchingOptionsNone, sourcePollTimeout, []routing.DataClient{dc}, 0}), OptionsNone) delay() p.ServeHTTP(w, r) if h, ok := w.Header()["X-Test-Response-Header"]; !ok || h[0] != "response header value" { t.Error("wrong response header") } }
func ExampleClient_FailNext() { // create a data client: dc, err := testdataclient.NewDoc(`Path("/some/path") -> "https://www.example.org"`) if err != nil || dc == nil { log.Fatal(err, dc == nil) } // set the the next two requests to fail: dc.FailNext() dc.FailNext() // wait for the third request to succeed: _, err = dc.LoadAll() fmt.Println(err) _, err = dc.LoadAll() fmt.Println(err) routes, err := dc.LoadAll() if err != nil || len(routes) != 1 { log.Fatal(err, len(routes)) } fmt.Println(routes[0].Backend) // Output: // failed to get routes // failed to get routes // https://www.example.org }
// TestNonMatchedStaticRoute for bug #116: non-matched static route supress wild-carded route func TestNonMatchedStaticRoute(t *testing.T) { dc, err := testdataclient.NewDoc(` a: Path("/foo/*_") -> "https://foo.org"; b: Path("/foo/bar") && CustomPredicate("custom1") -> "https://bar.org"; z: * -> "https://catch.all"`) if err != nil { t.Error(err) return } cps := []routing.PredicateSpec{&predicate{}} tr, err := newTestRoutingWithPredicates(cps, dc) if err != nil { t.Error(err) return } defer tr.close() req, err := http.NewRequest("GET", "https://www.example.com/foo/bar", nil) if err != nil { t.Error(err) return } if r, err := tr.checkRequest(req); r == nil || err != nil { t.Error(err) } else { if r.Backend != "https://foo.org" { t.Error("non-matched static route supress wild-carded route") } } }
func Example() { // create registry registry := builtin.MakeRegistry() // create and register the filter specification spec := &customSpec{name: "customFilter"} registry.Register(spec) // create simple data client, with route entries referencing 'customFilter', // and clipping part of the request path: dataClient, err := testdataclient.NewDoc(` ui: Path("/ui/*page") -> customFilter("ui request") -> modPath("^/[^/]*", "") -> "https://ui.example.org"; api: Path("/api/*resource") -> customFilter("api request") -> modPath("^/[^/]*", "") -> "https://api.example.org"`) if err != nil { log.Fatal(err) } // create http.Handler: proxy.New( routing.New(routing.Options{ FilterRegistry: registry, DataClients: []routing.DataClient{dataClient}}), proxy.OptionsNone) }
func TestProcessesPredicates(t *testing.T) { dc, err := testdataclient.NewDoc(` route1: CustomPredicate("custom1") -> "https://route1.example.org"; route2: CustomPredicate("custom2") -> "https://route2.example.org"; catchAll: * -> "https://route.example.org"`) if err != nil { t.Error(err) return } cps := []routing.PredicateSpec{&predicate{}, &predicate{}} rt := routing.New(routing.Options{ DataClients: []routing.DataClient{dc}, PollTimeout: pollTimeout, Predicates: cps}) req, err := http.NewRequest("GET", "https://www.example.com", nil) if err != nil { t.Error(err) return } req.Header.Set(predicateHeader, "custom1") select { case r := <-waitRoute(rt, req): if r.Backend != "https://route1.example.org" { t.Error("custom predicate matching failed, route1") return } case <-time.After(3 * pollTimeout): t.Error("test timeout") } req.Header.Set(predicateHeader, "custom2") select { case r := <-waitRoute(rt, req): if r.Backend != "https://route2.example.org" { t.Error("custom predicate matching failed, route2") return } case <-time.After(3 * pollTimeout): t.Error("test timeout") } req.Header.Del(predicateHeader) select { case r := <-waitRoute(rt, req): if r.Backend != "https://route.example.org" { t.Error("custom predicate matching failed, catch-all") return } case <-time.After(3 * pollTimeout): t.Error("test timeout") } }
func TestNoMultipleTreePredicates(t *testing.T) { for _, ti := range []struct { routes string err bool }{{ `Path("/foo") && Path("/bar") -> <shunt>`, true, }, { `Path("/foo") && PathSubtree("/bar") -> <shunt>`, true, }, { `PathSubtree("/foo") && PathSubtree("/bar") -> <shunt>`, true, }, { `Path("/foo") -> <shunt>`, false, }, { `PathSubtree("/foo") -> <shunt>`, false, }} { func() { dc, err := testdataclient.NewDoc(ti.routes) if err != nil { if !ti.err { t.Error(ti.routes, err) } return } defs, err := dc.LoadAll() if err != nil { if !ti.err { t.Error(ti.routes, err) } return } erred := false pr := make(map[string]PredicateSpec) fr := make(filters.Registry) for _, d := range defs { if _, err := processRouteDef(pr, fr, d); err != nil { erred = true break } } if erred != ti.err { t.Error("unexpected error result", erred, ti.err) } }() } }
func TestRoute(t *testing.T) { payload1 := []byte("host one") s1 := startTestServer(payload1, 0, voidCheck) defer s1.Close() payload2 := []byte("host two") s2 := startTestServer(payload2, 0, voidCheck) defer s2.Close() doc := fmt.Sprintf(` route1: Path("/host-one/*any") -> "%s"; route2: Path("/host-two/*any") -> "%s" `, s1.URL, s2.URL) dc, err := testdataclient.NewDoc(doc) if err != nil { t.Error(err) } p := New(routing.New(routing.Options{ nil, routing.MatchingOptionsNone, sourcePollTimeout, []routing.DataClient{dc}, nil, 0}), OptionsNone) delay() var ( r *http.Request w *httptest.ResponseRecorder u *url.URL ) u, _ = url.ParseRequestURI("https://www.example.org/host-one/some/path") r = &http.Request{ URL: u, Method: "GET"} w = httptest.NewRecorder() p.ServeHTTP(w, r) if w.Code != http.StatusOK || !bytes.Equal(w.Body.Bytes(), payload1) { t.Error("wrong routing 1") } u, _ = url.ParseRequestURI("https://www.example.org/host-two/some/path") r = &http.Request{ URL: u, Method: "GET"} w = httptest.NewRecorder() p.ServeHTTP(w, r) if w.Code != http.StatusOK || !bytes.Equal(w.Body.Bytes(), payload2) { t.Error("wrong routing 2") } }
func DisabledExample() { // create a target backend server. It will return the value of the 'X-Echo' request header // as the response body: targetServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(r.Header.Get("X-Echo"))) })) defer targetServer.Close() // create a filter registry, and register the custom filter: filterRegistry := builtin.MakeRegistry() filterRegistry.Register(&setEchoHeader{}) // create a data client with a predefined route, referencing the filter and a path condition // containing a wildcard called 'echo': routeDoc := fmt.Sprintf(`Path("/return/:echo") -> setEchoHeader() -> "%s"`, targetServer.URL) dataClient, err := testdataclient.NewDoc(routeDoc) if err != nil { log.Fatal(err) } // create routing object: rt := routing.New(routing.Options{ FilterRegistry: filterRegistry, DataClients: []routing.DataClient{dataClient}}) defer rt.Close() // create a proxy instance, and start an http server: proxy := proxy.New(rt, proxy.OptionsNone) defer proxy.Close() router := httptest.NewServer(proxy) defer router.Close() // make a request to the proxy: rsp, err := http.Get(fmt.Sprintf("%s/return/Hello,+world!", router.URL)) if err != nil { log.Fatal(err) } defer rsp.Body.Close() // print out the response: if _, err := io.Copy(os.Stdout, rsp.Body); err != nil { log.Fatal(err) } // Output: // Hello, world! }
func TestAppliesFilters(t *testing.T) { payload := []byte("Hello World!") s := startTestServer(payload, 0, func(r *http.Request) { if h, ok := r.Header["X-Test-Request-Header"]; !ok || h[0] != "request header value" { t.Error("request header is missing") } }) defer s.Close() u, _ := url.ParseRequestURI("https://www.example.org/hello") r := &http.Request{ URL: u, Method: "GET", Header: http.Header{"X-Test-Header": []string{"test value"}}} w := httptest.NewRecorder() fr := make(filters.Registry) fr.Register(builtin.NewRequestHeader()) fr.Register(builtin.NewResponseHeader()) doc := fmt.Sprintf(`hello: Path("/hello") -> requestHeader("X-Test-Request-Header", "request header value") -> responseHeader("X-Test-Response-Header", "response header value") -> "%s"`, s.URL) dc, err := testdataclient.NewDoc(doc) if err != nil { t.Error(err) } p := New(routing.New(routing.Options{ fr, routing.MatchingOptionsNone, sourcePollTimeout, []routing.DataClient{dc}, nil, 0}), OptionsNone) delay() p.ServeHTTP(w, r) if h, ok := w.Header()["X-Test-Response-Header"]; !ok || h[0] != "response header value" { t.Error("missing response header") } }
func TestFlusherImplementation(t *testing.T) { h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello, ")) time.Sleep(15 * time.Millisecond) w.Write([]byte("world!")) }) ts := httptest.NewServer(h) defer ts.Close() doc := fmt.Sprintf(`* -> "%s"`, ts.URL) dc, err := testdataclient.NewDoc(doc) if err != nil { t.Error(err) } p := New(routing.New(routing.Options{ nil, routing.MatchingOptionsNone, sourcePollTimeout, []routing.DataClient{dc}, nil, 0}), OptionsNone) delay() a := fmt.Sprintf(":%d", 1<<16-rand.Intn(1<<15)) ps := &http.Server{Addr: a, Handler: p} go ps.ListenAndServe() // let the server start listening time.Sleep(15 * time.Millisecond) rsp, err := http.Get("http://127.0.0.1" + a) if err != nil { t.Error(err) return } defer rsp.Body.Close() b, err := ioutil.ReadAll(rsp.Body) if err != nil { t.Error(err) return } if string(b) != "Hello, world!" { t.Error("failed to receive response") } }
func TestProcessesRequestWithPriorityRouteOverStandard(t *testing.T) { s0 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Test-Header", "priority-value") })) s1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Test-Header", "normal-value") })) req, err := http.NewRequest( "GET", "https://example.org/hello/world", nil) if err != nil { t.Error(err) } u, err := url.Parse(s0.URL) if err != nil { t.Error(err) } prt := &priorityRoute{&routing.Route{Scheme: u.Scheme, Host: u.Host}, nil, func(r *http.Request) bool { return r == req }} doc := fmt.Sprintf(`hello: Path("/hello") -> "%s"`, s1.URL) dc, err := testdataclient.NewDoc(doc) if err != nil { t.Error(err) } p := New(routing.New(routing.Options{ nil, routing.MatchingOptionsNone, sourcePollTimeout, []routing.DataClient{dc}, nil, 0}), OptionsNone, prt) delay() w := httptest.NewRecorder() p.ServeHTTP(w, req) if w.Header().Get("X-Test-Header") != "priority-value" { t.Error("failed match priority route") } }
func TestProcessesPredicates(t *testing.T) { dc, err := testdataclient.NewDoc(` route1: CustomPredicate("custom1") -> "https://route1.example.org"; route2: CustomPredicate("custom2") -> "https://route2.example.org"; catchAll: * -> "https://route.example.org"`) if err != nil { t.Error(err) return } cps := []routing.PredicateSpec{&predicate{}, &predicate{}} tr, err := newTestRoutingWithPredicates(cps, dc) if err != nil { t.Error(err) return } defer tr.close() req, err := http.NewRequest("GET", "https://www.example.com", nil) if err != nil { t.Error(err) return } req.Header.Set(predicateHeader, "custom1") if r, err := tr.checkRequest(req); r == nil || err != nil { t.Error(err) } else { if r.Backend != "https://route1.example.org" { t.Error("custom predicate matching failed, route1") return } } req.Header.Del(predicateHeader) if r, err := tr.checkRequest(req); r == nil || err != nil { t.Error(err) } else { if r.Backend != "https://route.example.org" { t.Error("custom predicate matching failed, catch-all") return } } }
func TestPostRoundtrip(t *testing.T) { s := startTestServer(nil, 0, func(r *http.Request) { if r.Method != "POST" { t.Error("wrong request method", r.Method) } if th, ok := r.Header["X-Test-Header"]; !ok || th[0] != "test value" { t.Error("wrong request header") } }) defer s.Close() u, _ := url.ParseRequestURI("https://www.example.org/hello") r := &http.Request{ URL: u, Method: "POST", Header: http.Header{"X-Test-Header": []string{"test value"}}} w := httptest.NewRecorder() doc := fmt.Sprintf(`hello: Path("/hello") -> "%s"`, s.URL) dc, err := testdataclient.NewDoc(doc) if err != nil { t.Error(err) } p := New(routing.New(routing.Options{ nil, routing.MatchingOptionsNone, sourcePollTimeout, []routing.DataClient{dc}, nil, 0}), OptionsNone) delay() p.ServeHTTP(w, r) if w.Code != http.StatusOK { t.Error("wrong status", w.Code) } if w.Body.Len() != 0 { t.Error("wrong content", string(w.Body.Bytes())) } }
func ExampleFilter() { // create a test filter and add to the registry: fr := builtin.MakeRegistry() fr.Register(&filtertest.Filter{FilterName: "testFilter"}) // create a data client, with a predefined route referencing the filter: dc, err := testdataclient.NewDoc(`Path("/some/path/:param") -> testFilter(3.14, "Hello, world!") -> "https://www.example.org"`) if err != nil { log.Fatal(err) } // create an http.Handler: proxy.New( routing.New(routing.Options{ DataClients: []routing.DataClient{dc}, FilterRegistry: fr}), proxy.OptionsNone) }
func ExamplePriorityRoute() { // create a routing doc forwarding all requests, // and load it in a data client: routeDoc := `* -> "https://www.example.org"` dataClient, err := testdataclient.NewDoc(routeDoc) if err != nil { log.Fatal(err) } // create a priority route making exceptions: pr := &priorityRoute{} // create an http.Handler: proxy.New( routing.New(routing.Options{ FilterRegistry: builtin.MakeRegistry(), DataClients: []routing.DataClient{dataClient}}), proxy.OptionsNone, pr) }
func newTestProxyWithFilters(fr filters.Registry, doc string, flags Flags, pr ...PriorityRoute) (*testProxy, error) { dc, err := testdataclient.NewDoc(doc) if err != nil { return nil, err } tl := loggingtest.New() rt := routing.New(routing.Options{ FilterRegistry: fr, PollTimeout: sourcePollTimeout, DataClients: []routing.DataClient{dc}, Log: tl}) p := WithParams(Params{Routing: rt, Flags: flags, PriorityRoutes: pr}) if err := tl.WaitFor("route settings applied", time.Second); err != nil { return nil, err } return &testProxy{tl, rt, p}, nil }
func TestOriginalRequestResponse(t *testing.T) { s := startTestServer(nil, 0, func(r *http.Request) { if th, ok := r.Header["X-Test-Header-Preserved"]; !ok || th[0] != "test value" { t.Error("wrong request header") } }) defer s.Close() u, _ := url.ParseRequestURI("https://www.example.org/hello") r := &http.Request{ URL: u, Method: "GET", Header: http.Header{"X-Test-Header": []string{"test value"}}} w := httptest.NewRecorder() doc := fmt.Sprintf(`hello: Path("/hello") -> preserveOriginal() -> "%s"`, s.URL) dc, err := testdataclient.NewDoc(doc) if err != nil { t.Error(err) } fr := builtin.MakeRegistry() fr.Register(&preserveOriginalSpec{}) p := New(routing.New(routing.Options{ fr, routing.MatchingOptionsNone, sourcePollTimeout, []routing.DataClient{dc}, nil, 0}), OptionsPreserveOriginal) delay() p.ServeHTTP(w, r) if th, ok := w.Header()["X-Test-Response-Header-Preserved"]; !ok || th[0] != "response header value" { t.Error("wrong response header", ok) } }
func Example() { // create a data client with a predefined route: dataClient, err := testdataclient.NewDoc( `Path("/some/path/to/:id") -> requestHeader("X-From", "skipper") -> "https://www.example.org"`) if err != nil { log.Fatal(err) } // create a router: r := routing.New(routing.Options{ FilterRegistry: builtin.MakeRegistry(), MatchingOptions: routing.IgnoreTrailingSlash, DataClients: []routing.DataClient{dataClient}}) // let the route data get propagated in the background: time.Sleep(36 * time.Millisecond) // create a request: req, err := http.NewRequest("GET", "https://www.example.com/some/path/to/Hello,+world!", nil) if err != nil { log.Fatal(err) } // match the request with the router: route, params := r.Route(req) if route == nil { log.Fatal("failed to route") } // verify the matched route and the path params: fmt.Println(route.Backend) fmt.Println(params["id"]) // Output: // https://www.example.org // Hello, world! }
func TestBreakFilterChain(t *testing.T) { s := startTestServer([]byte("Hello World!"), 0, func(r *http.Request) { t.Error("This should never be called") }) defer s.Close() fr := make(filters.Registry) fr.Register(builtin.NewRequestHeader()) resp1 := &http.Response{ Header: make(http.Header), Body: ioutil.NopCloser(new(bytes.Buffer)), StatusCode: http.StatusUnauthorized, Status: "Impossible body", } fr.Register(&breaker{resp1}) fr.Register(builtin.NewResponseHeader()) doc := fmt.Sprintf(`breakerDemo: Path("/breaker") -> requestHeader("X-Expected", "request header") -> responseHeader("X-Expected", "response header") -> breaker() -> requestHeader("X-Unexpected", "foo") -> responseHeader("X-Unexpected", "bar") -> "%s"`, s.URL) dc, err := testdataclient.NewDoc(doc) if err != nil { t.Error(err) } p := New(routing.New(routing.Options{ fr, routing.MatchingOptionsNone, sourcePollTimeout, []routing.DataClient{dc}, nil, 0}), OptionsNone) delay() r, _ := http.NewRequest("GET", "https://www.example.org/breaker", nil) w := httptest.NewRecorder() p.ServeHTTP(w, r) if _, has := r.Header["X-Expected"]; !has { t.Error("Request is missing the expected header (added during filter chain winding)") } if _, has := w.Header()["X-Expected"]; !has { t.Error("Response is missing the expected header (added during filter chain unwinding)") } if _, has := r.Header["X-Unexpected"]; has { t.Error("Request has an unexpected header from a filter after the breaker in the chain") } if _, has := w.Header()["X-Unexpected"]; has { t.Error("Response has an unexpected header from a filter after the breaker in the chain") } if w.Code != http.StatusUnauthorized && w.Body.String() != "Impossible body" { t.Errorf("Wrong status code/body. Expected 401 - Impossible body but got %d - %s", w.Code, w.Body.String()) } }
func TestHostHeader(t *testing.T) { // start a test backend that returns the received host header backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Received-Host", r.Host) })) // take the generated host part of the backend bu, err := url.Parse(backend.URL) if err != nil { t.Error("failed to parse test backend url") return } backendHost := bu.Host for _, ti := range []struct { msg string options Options routeFmt string incomingHost string expectedHost string }{{ "no proxy preserve", OptionsNone, `route: Any() -> "%s"`, "www.example.org", backendHost, }, { "no proxy preserve, route preserve not", OptionsNone, `route: Any() -> preserveHost("false") -> "%s"`, "www.example.org", backendHost, }, { "no proxy preserve, route preserve", OptionsNone, `route: Any() -> preserveHost("true") -> "%s"`, "www.example.org", "www.example.org", }, { "no proxy preserve, route preserve not, explicit host last", OptionsNone, `route: Any() -> preserveHost("false") -> requestHeader("Host", "custom.example.org") -> "%s"`, "www.example.org", "custom.example.org", }, { "no proxy preserve, route preserve, explicit host last", OptionsNone, `route: Any() -> preserveHost("true") -> requestHeader("Host", "custom.example.org") -> "%s"`, "www.example.org", "custom.example.org", }, { "no proxy preserve, route preserve not, explicit host first", OptionsNone, `route: Any() -> requestHeader("Host", "custom.example.org") -> preserveHost("false") -> "%s"`, "www.example.org", "custom.example.org", }, { "no proxy preserve, route preserve, explicit host last", OptionsNone, `route: Any() -> requestHeader("Host", "custom.example.org") -> preserveHost("true") -> "%s"`, "www.example.org", "custom.example.org", }, { "proxy preserve", OptionsProxyPreserveHost, `route: Any() -> "%s"`, "www.example.org", "www.example.org", }, { "proxy preserve, route preserve not", OptionsProxyPreserveHost, `route: Any() -> preserveHost("false") -> "%s"`, "www.example.org", backendHost, }, { "proxy preserve, route preserve", OptionsProxyPreserveHost, `route: Any() -> preserveHost("true") -> "%s"`, "www.example.org", "www.example.org", }, { "proxy preserve, route preserve not, explicit host last", OptionsProxyPreserveHost, `route: Any() -> preserveHost("false") -> requestHeader("Host", "custom.example.org") -> "%s"`, "www.example.org", "custom.example.org", }, { "proxy preserve, route preserve, explicit host last", OptionsProxyPreserveHost, `route: Any() -> preserveHost("true") -> requestHeader("Host", "custom.example.org") -> "%s"`, "www.example.org", "custom.example.org", }, { "proxy preserve, route preserve not, explicit host first", OptionsProxyPreserveHost, `route: Any() -> requestHeader("Host", "custom.example.org") -> preserveHost("false") -> "%s"`, "www.example.org", "custom.example.org", }, { "proxy preserve, route preserve, explicit host last", OptionsProxyPreserveHost, `route: Any() -> requestHeader("Host", "custom.example.org") -> preserveHost("true") -> "%s"`, "www.example.org", "custom.example.org", }} { // replace the host in the route format f := ti.routeFmt + `;healthcheck: Path("/healthcheck") -> "%s"` route := fmt.Sprintf(f, backend.URL, backend.URL) // create a dataclient with the route dc, err := testdataclient.NewDoc(route) if err != nil { t.Error(ti.msg, "failed to parse route") continue } // start a proxy server r := routing.New(routing.Options{ FilterRegistry: builtin.MakeRegistry(), MatchingOptions: routing.MatchingOptionsNone, PollTimeout: 42 * time.Microsecond, DataClients: []routing.DataClient{dc}}) ps := httptest.NewServer(New(r, ti.options)) // wait for the routing table was activated healthcheckDone := make(chan struct{}) go func() { for { rs, _ := http.Get(ps.URL + "/healthcheck") if rs != nil && rs.StatusCode >= http.StatusOK && rs.StatusCode < http.StatusMultipleChoices { healthcheckDone <- struct{}{} return } } }() timeouted := false select { case <-time.After(999 * time.Millisecond): timeouted = true case <-healthcheckDone: } if timeouted { t.Error(ti.msg, "startup timeout") ps.Close() continue } req, err := http.NewRequest("GET", ps.URL, nil) if err != nil { t.Error(ti.msg, err) ps.Close() continue } req.Host = ti.incomingHost rsp, err := (&http.Client{}).Do(req) if err != nil { t.Error(ti.msg, "failed to make request") ps.Close() continue } if rsp.Header.Get("X-Received-Host") != ti.expectedHost { t.Error(ti.msg, "wrong host", rsp.Header.Get("X-Received-Host"), ti.expectedHost) } ps.Close() } }
func ExampleNewDoc() { dc, err := testdataclient.NewDoc(`Path("/some/path") -> "https://www.example.org"`) if err != nil || dc == nil { log.Fatal(err, dc == nil) } }
func TestGetRoundtrip(t *testing.T) { payload := []byte("Hello World!") s := startTestServer(payload, 0, func(r *http.Request) { if r.Method != "GET" { t.Error("wrong request method") } if th, ok := r.Header["X-Test-Header"]; !ok || th[0] != "test value" { t.Error("wrong request header") } }) defer s.Close() u, _ := url.ParseRequestURI("https://www.example.org/hello") r := &http.Request{ URL: u, Method: "GET", Header: http.Header{"X-Test-Header": []string{"test value"}}} w := httptest.NewRecorder() doc := fmt.Sprintf(`hello: Path("/hello") -> "%s"`, s.URL) dc, err := testdataclient.NewDoc(doc) if err != nil { t.Error(err) } p := New(routing.New(routing.Options{ nil, routing.MatchingOptionsNone, sourcePollTimeout, []routing.DataClient{dc}, 0}), OptionsNone) delay() p.ServeHTTP(w, r) if w.Code != http.StatusOK { t.Error("wrong status", w.Code) } if ct, ok := w.Header()["Content-Type"]; !ok || ct[0] != "text/plain" { t.Error("wrong content type") } if cl, ok := w.Header()["Content-Length"]; !ok || cl[0] != strconv.Itoa(len(payload)) { t.Error("wrong content length") } if xpb, ok := w.Header()["X-Powered-By"]; !ok || xpb[0] != "Skipper" { t.Error("Wrong X-Powered-By header value") } if xpb, ok := w.Header()["Server"]; !ok || xpb[0] != "Skipper" { t.Error("Wrong Server header value") } if !bytes.Equal(w.Body.Bytes(), payload) { t.Error("wrong content", string(w.Body.Bytes())) } }