mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-01 14:47:38 +00:00
9ed5b872df
While at it, stop sending requests to unavailable backend for 3 seconds before the next attempt. This should reduce the amounts of useless work and the number of useless network packets when the backend is temporarily unavailable.
147 lines
4.4 KiB
Go
147 lines
4.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"testing"
|
|
)
|
|
|
|
func TestCreateTargetURLSuccess(t *testing.T) {
|
|
f := func(ui *UserInfo, requestURI, expectedTarget, expectedHeaders string) {
|
|
t.Helper()
|
|
u, err := url.Parse(requestURI)
|
|
if err != nil {
|
|
t.Fatalf("cannot parse %q: %s", requestURI, err)
|
|
}
|
|
u = normalizeURL(u)
|
|
up, headers, err := ui.getURLPrefixAndHeaders(u)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
bu := up.getLeastLoadedBackendURL()
|
|
target := mergeURLs(bu.url, u)
|
|
bu.put()
|
|
if target.String() != expectedTarget {
|
|
t.Fatalf("unexpected target; got %q; want %q", target, expectedTarget)
|
|
}
|
|
headersStr := fmt.Sprintf("%q", headers)
|
|
if headersStr != expectedHeaders {
|
|
t.Fatalf("unexpected headers; got %s; want %s", headersStr, expectedHeaders)
|
|
}
|
|
}
|
|
// Simple routing with `url_prefix`
|
|
f(&UserInfo{
|
|
URLPrefix: mustParseURL("http://foo.bar"),
|
|
}, "", "http://foo.bar/.", "[]")
|
|
f(&UserInfo{
|
|
URLPrefix: mustParseURL("http://foo.bar"),
|
|
Headers: []Header{{
|
|
Name: "bb",
|
|
Value: "aaa",
|
|
}},
|
|
}, "/", "http://foo.bar", `[{"bb" "aaa"}]`)
|
|
f(&UserInfo{
|
|
URLPrefix: mustParseURL("http://foo.bar/federate"),
|
|
}, "/", "http://foo.bar/federate", "[]")
|
|
f(&UserInfo{
|
|
URLPrefix: mustParseURL("http://foo.bar"),
|
|
}, "a/b?c=d", "http://foo.bar/a/b?c=d", "[]")
|
|
f(&UserInfo{
|
|
URLPrefix: mustParseURL("https://sss:3894/x/y"),
|
|
}, "/z", "https://sss:3894/x/y/z", "[]")
|
|
f(&UserInfo{
|
|
URLPrefix: mustParseURL("https://sss:3894/x/y"),
|
|
}, "/../../aaa", "https://sss:3894/x/y/aaa", "[]")
|
|
f(&UserInfo{
|
|
URLPrefix: mustParseURL("https://sss:3894/x/y"),
|
|
}, "/./asd/../../aaa?a=d&s=s/../d", "https://sss:3894/x/y/aaa?a=d&s=s%2F..%2Fd", "[]")
|
|
|
|
// Complex routing with `url_map`
|
|
ui := &UserInfo{
|
|
URLMaps: []URLMap{
|
|
{
|
|
SrcPaths: getSrcPaths([]string{"/api/v1/query"}),
|
|
URLPrefix: mustParseURL("http://vmselect/0/prometheus"),
|
|
Headers: []Header{
|
|
{
|
|
Name: "xx",
|
|
Value: "aa",
|
|
},
|
|
{
|
|
Name: "yy",
|
|
Value: "asdf",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
SrcPaths: getSrcPaths([]string{"/api/v1/write"}),
|
|
URLPrefix: mustParseURL("http://vminsert/0/prometheus"),
|
|
},
|
|
},
|
|
URLPrefix: mustParseURL("http://default-server"),
|
|
Headers: []Header{{
|
|
Name: "bb",
|
|
Value: "aaa",
|
|
}},
|
|
}
|
|
f(ui, "/api/v1/query?query=up", "http://vmselect/0/prometheus/api/v1/query?query=up", `[{"xx" "aa"} {"yy" "asdf"}]`)
|
|
f(ui, "/api/v1/write", "http://vminsert/0/prometheus/api/v1/write", "[]")
|
|
f(ui, "/api/v1/query_range", "http://default-server/api/v1/query_range", `[{"bb" "aaa"}]`)
|
|
|
|
// Complex routing regexp paths in `url_map`
|
|
ui = &UserInfo{
|
|
URLMaps: []URLMap{
|
|
{
|
|
SrcPaths: getSrcPaths([]string{"/api/v1/query(_range)?", "/api/v1/label/[^/]+/values"}),
|
|
URLPrefix: mustParseURL("http://vmselect/0/prometheus"),
|
|
},
|
|
{
|
|
SrcPaths: getSrcPaths([]string{"/api/v1/write"}),
|
|
URLPrefix: mustParseURL("http://vminsert/0/prometheus"),
|
|
},
|
|
},
|
|
URLPrefix: mustParseURL("http://default-server"),
|
|
}
|
|
f(ui, "/api/v1/query?query=up", "http://vmselect/0/prometheus/api/v1/query?query=up", "[]")
|
|
f(ui, "/api/v1/query_range?query=up", "http://vmselect/0/prometheus/api/v1/query_range?query=up", "[]")
|
|
f(ui, "/api/v1/label/foo/values", "http://vmselect/0/prometheus/api/v1/label/foo/values", "[]")
|
|
f(ui, "/api/v1/write", "http://vminsert/0/prometheus/api/v1/write", "[]")
|
|
f(ui, "/api/v1/foo/bar", "http://default-server/api/v1/foo/bar", "[]")
|
|
f(&UserInfo{
|
|
URLPrefix: mustParseURL("http://foo.bar?extra_label=team=dev"),
|
|
}, "/api/v1/query", "http://foo.bar/api/v1/query?extra_label=team=dev", "[]")
|
|
f(&UserInfo{
|
|
URLPrefix: mustParseURL("http://foo.bar?extra_label=team=mobile"),
|
|
}, "/api/v1/query?extra_label=team=dev", "http://foo.bar/api/v1/query?extra_label=team%3Dmobile", "[]")
|
|
|
|
}
|
|
|
|
func TestCreateTargetURLFailure(t *testing.T) {
|
|
f := func(ui *UserInfo, requestURI string) {
|
|
t.Helper()
|
|
u, err := url.Parse(requestURI)
|
|
if err != nil {
|
|
t.Fatalf("cannot parse %q: %s", requestURI, err)
|
|
}
|
|
u = normalizeURL(u)
|
|
up, headers, err := ui.getURLPrefixAndHeaders(u)
|
|
if err == nil {
|
|
t.Fatalf("expecting non-nil error")
|
|
}
|
|
if up != nil {
|
|
t.Fatalf("unexpected non-empty up=%#v", up)
|
|
}
|
|
if headers != nil {
|
|
t.Fatalf("unexpected non-empty headers=%q", headers)
|
|
}
|
|
}
|
|
f(&UserInfo{}, "/foo/bar")
|
|
f(&UserInfo{
|
|
URLMaps: []URLMap{
|
|
{
|
|
SrcPaths: getSrcPaths([]string{"/api/v1/query"}),
|
|
URLPrefix: mustParseURL("http://foobar/baz"),
|
|
},
|
|
},
|
|
}, "/api/v1/write")
|
|
}
|