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")
	}
}
Beispiel #4
0
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")
		}
	}
}
Beispiel #5
0
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
}
Beispiel #6
0
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)
	}
}
Beispiel #7
0
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)
	}
}
Beispiel #8
0
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)
	}
}
Beispiel #9
0
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")
	}
}
Beispiel #12
0
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)
	}
}
Beispiel #13
0
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")
	}
}
Beispiel #15
0
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)
	}
}
Beispiel #16
0
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
}
Beispiel #18
0
func ExampleNew() {
	testdataclient.New([]*eskip.Route{
		{Path: "/some/path", Backend: "https://www.example.org"}})
}
Beispiel #19
0
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()
		}
	}
}
Beispiel #20
0
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
}