func TestMergesMultipleSources(t *testing.T) { if testing.Short() { t.Skip() } dc1 := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "https://www.example.org"}}) dc2 := testdataclient.New([]*eskip.Route{{Id: "route2", Path: "/some-other", Backend: "https://other.example.org"}}) dc3 := testdataclient.New([]*eskip.Route{{Id: "route3", Path: "/another", Backend: "https://another.example.org"}}) rt := routing.New(routing.Options{ UpdateBuffer: 0, DataClients: []routing.DataClient{dc1, dc2, dc3}, PollTimeout: pollTimeout}) req1, err := http.NewRequest("GET", "https://www.example.com/some-path", nil) if err != nil { t.Error(err) } req2, err := http.NewRequest("GET", "https://www.example.com/some-other", nil) if err != nil { t.Error(err) } req3, err := http.NewRequest("GET", "https://www.example.com/another", nil) if err != nil { t.Error(err) } if !waitDone(6*pollTimeout, waitRoute(rt, req1), waitRoute(rt, req2), waitRoute(rt, req3)) { t.Error("test timeout") } }
func TestMergesUpdatesFromMultipleSources(t *testing.T) { dc1 := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "https://www.example.org"}}) dc2 := testdataclient.New([]*eskip.Route{{Id: "route2", Path: "/some-other", Backend: "https://other.example.org"}}) dc3 := testdataclient.New([]*eskip.Route{{Id: "route3", Path: "/another", Backend: "https://another.example.org"}}) rt := routing.New(routing.Options{ UpdateBuffer: 0, DataClients: []routing.DataClient{dc1, dc2, dc3}, PollTimeout: pollTimeout}) req1, err := http.NewRequest("GET", "https://www.example.com/some-path", nil) if err != nil { t.Error(err) } req2, err := http.NewRequest("GET", "https://www.example.com/some-other", nil) if err != nil { t.Error(err) } req3, err := http.NewRequest("GET", "https://www.example.com/another", nil) if err != nil { t.Error(err) } waitRoute(rt, req1) waitRoute(rt, req2) waitRoute(rt, req3) <-waitUpdate(dc1, []*eskip.Route{{Id: "route1", Path: "/some-changed-path", Backend: "https://www.example.org"}}, nil, false) <-waitUpdate(dc2, []*eskip.Route{{Id: "route2", Path: "/some-other-changed", Backend: "https://www.example.org"}}, nil, false) <-waitUpdate(dc3, nil, []string{"route3"}, false) req1, err = http.NewRequest("GET", "https://www.example.com/some-changed-path", nil) if err != nil { t.Error(err) } req2, err = http.NewRequest("GET", "https://www.example.com/some-other-changed", nil) if err != nil { t.Error(err) } req3, err = http.NewRequest("GET", "https://www.example.com/another", nil) if err != nil { t.Error(err) } if !waitDone(6*pollTimeout, waitRoute(rt, req1), waitRoute(rt, req2)) { t.Error("test timeout") } time.Sleep(3 * pollTimeout) if waitDone(0, waitRoute(rt, req3)) { t.Error("should not have found route") } }
func TestReceivesDelete(t *testing.T) { dc := testdataclient.New([]*eskip.Route{ {Id: "route1", Path: "/some-path", Backend: "https://www.example.org"}, {Id: "route2", Path: "/some-other", Backend: "https://other.example.org"}}) rt := routing.New(routing.Options{ UpdateBuffer: 0, DataClients: []routing.DataClient{dc}, PollTimeout: pollTimeout}) req, err := http.NewRequest("GET", "https://www.example.com/some-path", nil) if err != nil { t.Error(err) } <-waitRoute(rt, req) <-waitUpdate(dc, nil, []string{"route1"}, false) time.Sleep(6 * pollTimeout) req, err = http.NewRequest("GET", "https://www.example.com/some-path", nil) if err != nil { t.Error(err) } if waitDone(0, waitRoute(rt, req)) { t.Error("should not have found route") } }
func TestProcessesFilterDefinitions(t *testing.T) { fr := make(filters.Registry) fs := &filtertest.Filter{FilterName: "filter1"} fr.Register(fs) dc := testdataclient.New([]*eskip.Route{{ Id: "route1", Path: "/some-path", Filters: []*eskip.Filter{{Name: "filter1", Args: []interface{}{3.14, "Hello, world!"}}}, Backend: "https://www.example.org"}}) tr, err := newTestRoutingWithFilters(fr, dc) if err != nil { t.Error(err) return } defer tr.close() if r, err := tr.checkGetRequest("https://www.example.com/some-path"); r == nil || err != nil { t.Error(err) } else { if len(r.Filters) != 1 { t.Error("failed to process filters") return } if f, ok := r.Filters[0].Filter.(*filtertest.Filter); !ok || f.FilterName != fs.Name() || len(f.Args) != 2 || f.Args[0] != float64(3.14) || f.Args[1] != "Hello, world!" { t.Error("failed to process filters") } } }
func Example() { // create a data client: dataClient := testdataclient.New([]*eskip.Route{ {Path: "/some/path", Backend: "https://www.example.org"}}) // (only in tests) tl := loggingtest.New() defer tl.Close() // create a router: r := routing.New(routing.Options{ DataClients: []routing.DataClient{dataClient}, Log: tl}) defer r.Close() // wait for the route data being propagated: tl.WaitFor("route settigns applied", time.Second) // test the router: route, _ := r.Route(&http.Request{URL: &url.URL{Path: "/some/path"}}) if route == nil { log.Fatal("failed to route request") } fmt.Println(route.Backend) // Output: // https://www.example.org }
func TestMergesUpdatesFromMultipleSources(t *testing.T) { dc1 := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "https://www.example.org"}}) dc2 := testdataclient.New([]*eskip.Route{{Id: "route2", Path: "/some-other", Backend: "https://other.example.org"}}) dc3 := testdataclient.New([]*eskip.Route{{Id: "route3", Path: "/another", Backend: "https://another.example.org"}}) tr, err := newTestRouting(dc1, dc2, dc3) if err != nil { t.Error(err) return } defer tr.close() if _, err := tr.checkGetRequest("https://www.example.com/some-path"); err != nil { t.Error(err) } if _, err := tr.checkGetRequest("https://www.example.com/some-other"); err != nil { t.Error(err) } if _, err := tr.checkGetRequest("https://www.example.com/another"); err != nil { t.Error(err) } tr.log.Reset() dc1.Update([]*eskip.Route{{Id: "route1", Path: "/some-changed-path", Backend: "https://www.example.org"}}, nil) dc2.Update([]*eskip.Route{{Id: "route2", Path: "/some-other-changed", Backend: "https://www.example.org"}}, nil) dc3.Update(nil, []string{"route3"}) if err := tr.waitForNRouteSettings(3); err != nil { t.Error(err) return } if _, err := tr.checkGetRequest("https://www.example.com/some-changed-path"); err != nil { t.Error(err) } if _, err := tr.checkGetRequest("https://www.example.com/some-other-changed"); err != nil { t.Error(err) } if _, err := tr.checkGetRequest("https://www.example.com/another"); err == nil { t.Error(err) } }
func TestReceivesInitial(t *testing.T) { dc := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "https://www.example.org"}}) tr, err := newTestRouting(dc) if err != nil { t.Error(err) } defer tr.close() if _, err := tr.checkGetRequest("https://www.example.com/some-path"); err != nil { t.Error(err) } }
func TestIgnoresInvalidBackend(t *testing.T) { dc := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "invalid backend"}}) tr, err := newTestRouting(dc) if err != nil { t.Error(err) } defer tr.close() if err = tr.log.WaitFor("invalid backend", time.Second); err != nil { t.Error(err) } }
func TestMergesMultipleSources(t *testing.T) { dc1 := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "https://www.example.org"}}) dc2 := testdataclient.New([]*eskip.Route{{Id: "route2", Path: "/some-other", Backend: "https://other.example.org"}}) dc3 := testdataclient.New([]*eskip.Route{{Id: "route3", Path: "/another", Backend: "https://another.example.org"}}) tr, err := newTestRouting(dc1, dc2, dc3) if err != nil { t.Error(err) return } defer tr.close() if _, err := tr.checkGetRequest("https://www.example.com/some-path"); err != nil { t.Error(err) } if _, err := tr.checkGetRequest("https://www.example.com/some-other"); err != nil { t.Error(err) } if _, err := tr.checkGetRequest("https://www.example.com/another"); err != nil { t.Error(err) } }
func TestIgnoresInvalidBackend(t *testing.T) { dc := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "invalid backend"}}) rt := routing.New(routing.Options{ UpdateBuffer: 0, DataClients: []routing.DataClient{dc}, PollTimeout: pollTimeout}) req, err := http.NewRequest("GET", "https://www.example.com/some-path", nil) if err != nil { t.Error(err) } if waitDone(6*pollTimeout, waitRoute(rt, req)) { t.Error("should not have found route") } }
func TestReceivesInitial(t *testing.T) { dc := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "https://www.example.org"}}) rt := routing.New(routing.Options{ UpdateBuffer: 0, DataClients: []routing.DataClient{dc}, PollTimeout: pollTimeout}) req, err := http.NewRequest("GET", "https://www.example.com/some-path", nil) if err != nil { t.Error(err) } if !waitDone(6*pollTimeout, waitRoute(rt, req)) { t.Error("test timeout") } }
func TestKeepsReceivingInitialRouteDataUntilSucceeds(t *testing.T) { dc := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "https://www.example.org"}}) dc.FailNext() dc.FailNext() dc.FailNext() tr, err := newTestRouting(dc) if err != nil { t.Error(err) return } defer tr.close() if _, err := tr.checkGetRequest("https://www.example.com/some-path"); err != nil { t.Error(err) } }
func WithParams(fr filters.Registry, o proxy.Params, routes ...*eskip.Route) *TestProxy { dc := testdataclient.New(routes) tl := loggingtest.New() rt := routing.New(routing.Options{FilterRegistry: fr, DataClients: []routing.DataClient{dc}, Log: tl}) o.Routing = rt pr := proxy.WithParams(o) tsp := httptest.NewServer(pr) if err := tl.WaitFor("route settings applied", 3*time.Second); err != nil { panic(err) } return &TestProxy{ URL: tsp.URL, log: tl, routing: rt, proxy: pr, server: tsp} }
func TestProcessesFilterDefinitions(t *testing.T) { if testing.Short() { t.Skip() } fr := make(filters.Registry) fs := &filtertest.Filter{FilterName: "filter1"} fr.Register(fs) dc := testdataclient.New([]*eskip.Route{{ Id: "route1", Path: "/some-path", Filters: []*eskip.Filter{{Name: "filter1", Args: []interface{}{3.14, "Hello, world!"}}}, Backend: "https://www.example.org"}}) rt := routing.New(routing.Options{ UpdateBuffer: 0, DataClients: []routing.DataClient{dc}, PollTimeout: pollTimeout, FilterRegistry: fr}) req, err := http.NewRequest("GET", "https://www.example.com/some-path", nil) if err != nil { t.Error(err) } select { case r := <-waitRoute(rt, req): if len(r.Filters) != 1 { t.Error("failed to process filters") return } if f, ok := r.Filters[0].Filter.(*filtertest.Filter); !ok || f.FilterName != fs.Name() || len(f.Args) != 2 || f.Args[0] != float64(3.14) || f.Args[1] != "Hello, world!" { t.Error("failed to process filters") } case <-time.After(3 * pollTimeout): t.Error("test timeout") } }
func TestReceivesUpdate(t *testing.T) { dc := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "https://www.example.org"}}) tr, err := newTestRouting(dc) if err != nil { t.Error(err) return } defer tr.close() tr.log.Reset() dc.Update([]*eskip.Route{{Id: "route2", Path: "/some-other", Backend: "https://other.example.org"}}, nil) if err := tr.waitForRouteSetting(); err != nil { t.Error(err) return } if _, err := tr.checkGetRequest("https://www.example.com/some-other"); err != nil { t.Error(err) } }
func TestUpdateDoesNotChangeRouting(t *testing.T) { dc := testdataclient.New([]*eskip.Route{{Id: "route1", Path: "/some-path", Backend: "https://www.example.org"}}) tr, err := newTestRouting(dc) if err != nil { t.Error(err) return } defer tr.close() tr.log.Reset() dc.Update(nil, nil) if err := tr.waitForNRouteSettingsTO(1, 3*pollTimeout); err != nil && err != loggingtest.ErrWaitTimeout { t.Error(err) return } if _, err := tr.checkGetRequest("https://www.example.com/some-path"); err != nil { t.Error(err) } }
func Example() { // create a data client: dataClient := testdataclient.New([]*eskip.Route{ {Path: "/some/path", Backend: "https://www.example.org"}}) // create a router: r := routing.New(routing.Options{ DataClients: []routing.DataClient{dataClient}}) // let the route data be propagated: time.Sleep(36 * time.Millisecond) // test the router: route, _ := r.Route(&http.Request{URL: &url.URL{Path: "/some/path"}}) if route == nil { log.Fatal("failed to route request") } fmt.Println(route.Backend) // Output: // https://www.example.org }
func ExampleNew() { testdataclient.New([]*eskip.Route{ {Path: "/some/path", Backend: "https://www.example.org"}}) }
func TestRedirect(t *testing.T) { for _, ti := range []struct { msg string code int filterLocation string checkLocation string }{{ "schema only", http.StatusFound, "http:", "http://incoming.example.org/some/path?foo=1&bar=2", }, { "schema and host", http.StatusFound, "http://redirect.example.org", "http://redirect.example.org/some/path?foo=1&bar=2", }, { "schema, host and path", http.StatusFound, "http://redirect.example.org/some/other/path", "http://redirect.example.org/some/other/path?foo=1&bar=2", }, { "schema, host, path and query", http.StatusFound, "http://redirect.example.org/some/other/path?newquery=3", "http://redirect.example.org/some/other/path?newquery=3", }, { "host only", http.StatusFound, "//redirect.example.org", "https://redirect.example.org/some/path?foo=1&bar=2", }, { "host and path", http.StatusFound, "//redirect.example.org/some/other/path", "https://redirect.example.org/some/other/path?foo=1&bar=2", }, { "host, path and query", http.StatusFound, "//redirect.example.org/some/other/path?newquery=3", "https://redirect.example.org/some/other/path?newquery=3", }, { "path only", http.StatusFound, "/some/other/path", "https://incoming.example.org/some/other/path?foo=1&bar=2", }, { "path and query", http.StatusFound, "/some/other/path?newquery=3", "https://incoming.example.org/some/other/path?newquery=3", }, { "query only", http.StatusFound, "?newquery=3", "https://incoming.example.org/some/path?newquery=3", }, { "schema and path", http.StatusFound, "http:///some/other/path", "http://incoming.example.org/some/other/path?foo=1&bar=2", }, { "schema, path and query", http.StatusFound, "http:///some/other/path?newquery=3", "http://incoming.example.org/some/other/path?newquery=3", }, { "schema and query", http.StatusFound, "http://?newquery=3", "http://incoming.example.org/some/path?newquery=3", }, { "different code", http.StatusMovedPermanently, "/some/path", "https://incoming.example.org/some/path?foo=1&bar=2", }} { for _, tii := range []struct { msg string name string }{{ "deprecated", RedirectName, }, { "not deprecated", RedirectToName, }} { dc := testdataclient.New([]*eskip.Route{{ Shunt: true, Filters: []*eskip.Filter{{ Name: tii.name, Args: []interface{}{float64(ti.code), ti.filterLocation}}}}}) tl := loggingtest.New() rt := routing.New(routing.Options{ FilterRegistry: MakeRegistry(), DataClients: []routing.DataClient{dc}, Log: tl}) p := proxy.New(rt, proxy.OptionsNone) closeAll := func() { p.Close() rt.Close() tl.Close() } // pick up routing if err := tl.WaitFor("route settings applied", time.Second); err != nil { t.Error(err) closeAll() continue } req := &http.Request{ URL: &url.URL{Path: "/some/path", RawQuery: "foo=1&bar=2"}, Host: "incoming.example.org"} w := httptest.NewRecorder() p.ServeHTTP(w, req) if w.Code != ti.code { t.Error(ti.msg, tii.msg, "invalid status code", w.Code) } if w.Header().Get("Location") != ti.checkLocation { t.Error(ti.msg, tii.msg, "invalid location", w.Header().Get("Location")) } closeAll() } } }
func DisabledExampleClient_Update() { // create a data client: dc := testdataclient.New([]*eskip.Route{ {Id: "route1", Path: "/some/path", Backend: "https://www1.example.org"}, {Id: "route2", Path: "/some/path", Backend: "https://www2.example.org"}}) // check initial routes: routes, err := dc.LoadAll() if err != nil { log.Fatal(err) } fmt.Println() fmt.Println("before update:") for _, r := range routes { fmt.Println(r.Backend) } // send an update: go func() { dc.Update( []*eskip.Route{{Id: "route1", Path: "/some/path", Backend: "https://mod.example.org"}}, []string{"route2"}) }() // receive the update: routes, deletedIds, err := dc.LoadUpdate() if err != nil { log.Fatal(err) } fmt.Println() fmt.Println("update:") for _, r := range routes { fmt.Println(r.Backend) } for _, id := range deletedIds { fmt.Println(id) } // check all routes again: routes, err = dc.LoadAll() if err != nil { log.Fatal(err) } fmt.Println() fmt.Println("after update:") for _, r := range routes { fmt.Println(r.Backend) } // Output: // // before update: // https://www1.example.org // https://www2.example.org // // update: // https://mod.example.org // route2 // // after update: // https://mod.example.org }