lib: consistently use f-tests instead of table-driven tests

This makes easier to read and debug these tests. This also reduces test lines count by 15% from 3K to 2.5K
See https://itnext.io/f-tests-as-a-replacement-for-table-driven-tests-in-go-8814a8b19e9e

While at it, consistently use t.Fatal* instead of t.Error*, since t.Error* usually leads
to more complicated and fragile tests, while it doesn't bring any practical benefits over t.Fatal*.
This commit is contained in:
Aliaksandr Valialkin 2024-07-09 22:32:54 +02:00
parent 662e026279
commit a9525da8a4
No known key found for this signature in database
GPG key ID: 52C003EE2BCDB9EB
35 changed files with 1795 additions and 2272 deletions

View file

@ -135,9 +135,13 @@ func TestAuthKeyMetrics(t *testing.T) {
}
func TestHandlerWrapper(t *testing.T) {
*headerHSTS = "foo"
*headerFrameOptions = "bar"
*headerCSP = "baz"
const hstsHeader = "foo"
const frameOptionsHeader = "bar"
const cspHeader = "baz"
*headerHSTS = hstsHeader
*headerFrameOptions = frameOptionsHeader
*headerCSP = cspHeader
defer func() {
*headerHSTS = ""
*headerFrameOptions = ""
@ -152,13 +156,14 @@ func TestHandlerWrapper(t *testing.T) {
return true
})
if w.Header().Get("Strict-Transport-Security") != "foo" {
t.Errorf("HSTS header not set")
h := w.Header()
if got := h.Get("Strict-Transport-Security"); got != hstsHeader {
t.Fatalf("unexpected HSTS header; got %q; want %q", got, hstsHeader)
}
if w.Header().Get("X-Frame-Options") != "bar" {
t.Errorf("X-Frame-Options header not set")
if got := h.Get("X-Frame-Options"); got != frameOptionsHeader {
t.Fatalf("unexpected X-Frame-Options header; got %q; want %q", got, frameOptionsHeader)
}
if w.Header().Get("Content-Security-Policy") != "baz" {
t.Errorf("CSP header not set")
if got := h.Get("Content-Security-Policy"); got != cspHeader {
t.Fatalf("unexpected CSP header; got %q; want %q", got, cspHeader)
}
}

View file

@ -9,28 +9,27 @@ func TestTLSConfig(t *testing.T) {
insecureSkipVerify = true
tlsCfg, err := TLSConfig(certFile, keyFile, CAFile, serverName, insecureSkipVerify)
if err != nil {
t.Errorf("unexpected error %s", err)
t.Fatalf("unexpected error %s", err)
}
if tlsCfg == nil {
t.Errorf("expected tlsConfig to be set, got nil")
return
t.Fatalf("expected tlsConfig to be set, got nil")
}
if tlsCfg.ServerName != serverName {
t.Errorf("unexpected ServerName, want %s, got %s", serverName, tlsCfg.ServerName)
t.Fatalf("unexpected ServerName, want %s, got %s", serverName, tlsCfg.ServerName)
}
if tlsCfg.InsecureSkipVerify != insecureSkipVerify {
t.Errorf("unexpected InsecureSkipVerify, want %v, got %v", insecureSkipVerify, tlsCfg.InsecureSkipVerify)
t.Fatalf("unexpected InsecureSkipVerify, want %v, got %v", insecureSkipVerify, tlsCfg.InsecureSkipVerify)
}
certFile = "/path/to/nonexisting/cert/file"
_, err = TLSConfig(certFile, keyFile, CAFile, serverName, insecureSkipVerify)
if err == nil {
t.Errorf("expected keypair error, got nil")
t.Fatalf("expected keypair error, got nil")
}
certFile = ""
CAFile = "/path/to/nonexisting/cert/file"
_, err = TLSConfig(certFile, keyFile, CAFile, serverName, insecureSkipVerify)
if err == nil {
t.Errorf("expected read error, got nil")
t.Fatalf("expected read error, got nil")
}
}
@ -40,14 +39,14 @@ func TestTransport(t *testing.T) {
URL := "http://victoriametrics.com"
_, err := Transport(URL, certFile, keyFile, CAFile, serverName, insecureSkipVerify)
if err != nil {
t.Errorf("unexpected error %s", err)
t.Fatalf("unexpected error %s", err)
}
URL = "https://victoriametrics.com"
tr, err := Transport(URL, certFile, keyFile, CAFile, serverName, insecureSkipVerify)
if err != nil {
t.Errorf("unexpected error %s", err)
t.Fatalf("unexpected error %s", err)
}
if tr.TLSClientConfig == nil {
t.Errorf("expected TLSClientConfig to be set, got nil")
t.Fatalf("expected TLSClientConfig to be set, got nil")
}
}

View file

@ -129,8 +129,7 @@ func TestParseTenantID(t *testing.T) {
got, err := ParseTenantID(tenant)
if err != nil {
t.Errorf("unexpected error: %s", err)
return
t.Fatalf("unexpected error: %s", err)
}
if got.String() != expected.String() {

View file

@ -5,20 +5,21 @@ import (
"testing"
)
func Test_parseAPIResponse(t *testing.T) {
type args struct {
data []byte
}
tests := []struct {
name string
args args
want *listDropletResponse
wantErr bool
}{
func TestParseAPIResponse(t *testing.T) {
f := func(data string, responseExpected *listDropletResponse) {
t.Helper()
response, err := parseAPIResponse([]byte(data))
if err != nil {
t.Fatalf("unexpected parseAPIResponse() error: %s", err)
}
if !reflect.DeepEqual(response, responseExpected) {
t.Fatalf("unexpected response\ngot\n%v\nwant\n%v", response, responseExpected)
}
}
data := `
{
name: "simple parse",
args: args{data: []byte(`{
"droplets": [
{
"id": 3164444,
@ -88,20 +89,18 @@ func Test_parseAPIResponse(t *testing.T) {
"next": "https://api.digitalocean.com/v2/droplets?page=2&per_page=1"
}
}
}`)},
want: &listDropletResponse{
}`
responseExpected := &listDropletResponse{
Droplets: []droplet{
{
Image: struct {
Name string `json:"name"`
Slug string `json:"slug"`
}(struct {
Name string
Slug string
}{Name: "14.04 x64", Slug: "ubuntu-16-04-x64"}),
Region: struct {
Slug string `json:"slug"`
}(struct{ Slug string }{Slug: "nyc3"}),
Image: dropletImage{
Name: "14.04 x64",
Slug: "ubuntu-16-04-x64",
},
Region: dropletRegion{
Slug: "nyc3",
},
Networks: networks{
V6: []network{
{
@ -126,45 +125,29 @@ func Test_parseAPIResponse(t *testing.T) {
},
},
Links: links{
Pages: struct {
Last string `json:"last,omitempty"`
Next string `json:"next,omitempty"`
}(struct {
Last string
Next string
}{Last: "https://api.digitalocean.com/v2/droplets?page=3&per_page=1", Next: "https://api.digitalocean.com/v2/droplets?page=2&per_page=1"}),
},
Pages: linksPages{
Last: "https://api.digitalocean.com/v2/droplets?page=3&per_page=1",
Next: "https://api.digitalocean.com/v2/droplets?page=2&per_page=1",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseAPIResponse(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("parseAPIResponse() error = %v, wantErr %v", err, tt.wantErr)
return
f(data, responseExpected)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseAPIResponse() got = \n%v\n, \nwant \n%v\n", got, tt.want)
func TestGetDroplets(t *testing.T) {
f := func(getAPIResponse func(string) ([]byte, error), expectedDropletCount int) {
t.Helper()
resp, err := getDroplets(getAPIResponse)
if err != nil {
t.Fatalf("getDroplets() error: %s", err)
}
})
if len(resp) != expectedDropletCount {
t.Fatalf("unexpected droplets count; got %d; want %d\ndroplets:\n%v", len(resp), expectedDropletCount, resp)
}
}
func Test_getDroplets(t *testing.T) {
type args struct {
getAPIResponse func(string) ([]byte, error)
}
tests := []struct {
name string
args args
wantDropletCount int
wantErr bool
}{
{
name: "get 4 droples",
args: args{
func(s string) ([]byte, error) {
getAPIResponse := func(s string) ([]byte, error) {
var resp []byte
switch s {
case dropletsAPIPath:
@ -328,22 +311,6 @@ func Test_getDroplets(t *testing.T) {
}`)
}
return resp, nil
},
},
wantDropletCount: 5,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := getDroplets(tt.args.getAPIResponse)
if (err != nil) != tt.wantErr {
t.Errorf("getDroplets() error = %v, wantErr %v", err, tt.wantErr)
return
}
if len(got) != tt.wantDropletCount {
t.Fatalf("unexpected droplets count: %d, want: %d, \n droplets: %v\n", len(got), tt.wantDropletCount, got)
}
})
}
f(getAPIResponse, 5)
}

View file

@ -50,19 +50,23 @@ type droplet struct {
Status string `json:"status"`
Features []string `json:"features"`
Image struct {
Name string `json:"name"`
Slug string `json:"slug"`
} `json:"image"`
Image dropletImage `json:"image"`
SizeSlug string `json:"size_slug"`
Networks networks `json:"networks"`
Region struct {
Slug string `json:"slug"`
} `json:"region"`
Region dropletRegion `json:"region"`
Tags []string `json:"tags"`
VpcUUID string `json:"vpc_uuid"`
}
type dropletImage struct {
Name string `json:"name"`
Slug string `json:"slug"`
}
type dropletRegion struct {
Slug string `json:"slug"`
}
func (d *droplet) getIPByNet(netVersion, netType string) string {
var dropletNetworks []network
switch netVersion {
@ -98,10 +102,12 @@ type listDropletResponse struct {
}
type links struct {
Pages struct {
Pages linksPages `json:"pages,omitempty"`
}
type linksPages struct {
Last string `json:"last,omitempty"`
Next string `json:"next,omitempty"`
} `json:"pages,omitempty"`
}
func (r *listDropletResponse) nextURLPath() (string, error) {

View file

@ -7,38 +7,31 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_addDropletLabels(t *testing.T) {
type args struct {
droplets []droplet
defaultPort int
func TestAddDropletLabels(t *testing.T) {
f := func(droplets []droplet, labelssExpected []*promutils.Labels) {
t.Helper()
labelss := addDropletLabels(droplets, 9100)
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
{
name: "base labels add test",
args: args{
droplets: []droplet{
// base labels add test
droplets := []droplet{
{
ID: 15,
Tags: []string{"private", "test"},
Status: "active",
Name: "ubuntu-1",
Region: struct {
Slug string `json:"slug"`
}(struct{ Slug string }{Slug: "do"}),
Region: dropletRegion{
Slug: "do",
},
Features: []string{"feature-1", "feature-2"},
SizeSlug: "base-1",
VpcUUID: "vpc-1",
Image: struct {
Name string `json:"name"`
Slug string `json:"slug"`
}(struct {
Name string
Slug string
}{Name: "ubuntu", Slug: "18"}),
Image: dropletImage{
Name: "ubuntu",
Slug: "18",
},
Networks: networks{
V4: []network{
{
@ -58,10 +51,8 @@ func Test_addDropletLabels(t *testing.T) {
},
},
},
},
defaultPort: 9100,
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "100.100.100.100:9100",
"__meta_digitalocean_droplet_id": "15",
@ -78,13 +69,6 @@ func Test_addDropletLabels(t *testing.T) {
"__meta_digitalocean_tags": ",private,test,",
"__meta_digitalocean_vpc": "vpc-1",
}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := addDropletLabels(tt.args.droplets, tt.args.defaultPort)
discoveryutils.TestEqualLabelss(t, got, tt.want)
})
}
f(droplets, labelssExpected)
}

View file

@ -14,22 +14,30 @@ type container struct {
ID string
Names []string
Labels map[string]string
Ports []struct {
Ports []containerPort
HostConfig containerHostConfig
NetworkSettings containerNetworkSettings
}
type containerPort struct {
IP string
PrivatePort int
PublicPort int
Type string
}
HostConfig struct {
type containerHostConfig struct {
NetworkMode string
}
NetworkSettings struct {
Networks map[string]struct {
type containerNetworkSettings struct {
Networks map[string]containerNetwork
}
type containerNetwork struct {
IPAddress string
NetworkID string
}
}
}
func getContainersLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
networkLabels, err := getNetworksLabelsByNetworkID(cfg)

View file

@ -8,20 +8,20 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_parseContainers(t *testing.T) {
type args struct {
data []byte
func TePParseContainers(t *testing.T) {
f := func(data string, resultExpected []container) {
t.Helper()
result, err := parseContainers([]byte(data))
if err != nil {
t.Fatalf("parseContainers() error: %s", err)
}
tests := []struct {
name string
args args
want []container
wantErr bool
}{
{
name: "parse two containers",
args: args{
data: []byte(`[
if !reflect.DeepEqual(result, resultExpected) {
t.Fatalf("unexpected result\ngot\n%v\nwant\n%v", result, resultExpected)
}
}
data := `[
{
"Id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
"Names": [
@ -116,9 +116,8 @@ func Test_parseContainers(t *testing.T) {
}
}
}
]`),
},
want: []container{
]`
resultExpected := []container{
{
ID: "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
Names: []string{"/crow-server"},
@ -130,32 +129,19 @@ func Test_parseContainers(t *testing.T) {
"com.docker.compose.service": "crow-server",
"com.docker.compose.version": "1.11.2",
},
Ports: []struct {
IP string
PrivatePort int
PublicPort int
Type string
}{{
Ports: []containerPort{
{
IP: "0.0.0.0",
PrivatePort: 8080,
PublicPort: 18081,
Type: "tcp",
}},
HostConfig: struct {
NetworkMode string
}{
},
},
HostConfig: containerHostConfig{
NetworkMode: "bridge",
},
NetworkSettings: struct {
Networks map[string]struct {
IPAddress string
NetworkID string
}
}{
Networks: map[string]struct {
IPAddress string
NetworkID string
}{
NetworkSettings: containerNetworkSettings{
Networks: map[string]containerNetwork{
"bridge": {
IPAddress: "172.17.0.2",
NetworkID: "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
@ -174,32 +160,19 @@ func Test_parseContainers(t *testing.T) {
"com.docker.compose.service": "crow-web",
"com.docker.compose.version": "1.11.2",
},
Ports: []struct {
IP string
PrivatePort int
PublicPort int
Type string
}{{
Ports: []containerPort{
{
IP: "0.0.0.0",
PrivatePort: 8080,
PublicPort: 18082,
Type: "tcp",
}},
HostConfig: struct {
NetworkMode string
}{
},
},
HostConfig: containerHostConfig{
NetworkMode: "bridge",
},
NetworkSettings: struct {
Networks map[string]struct {
IPAddress string
NetworkID string
}
}{
Networks: map[string]struct {
IPAddress string
NetworkID string
}{
NetworkSettings: containerNetworkSettings{
Networks: map[string]containerNetwork{
"bridge": {
IPAddress: "172.17.0.3",
NetworkID: "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
@ -207,24 +180,19 @@ func Test_parseContainers(t *testing.T) {
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseContainers(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("parseContainers() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseNetworks() \ngot %v, \nwant %v", got, tt.want)
}
})
}
}
func Test_addContainerLabels(t *testing.T) {
f(data, resultExpected)
}
func TestAddContainerLabels(t *testing.T) {
f := func(c container, networkLabels map[string]*promutils.Labels, labelssExpected []*promutils.Labels) {
t.Helper()
labelss := addContainersLabels([]container{c}, networkLabels, 8012, "foobar")
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
data := []byte(`[
{
"Name": "host",
@ -314,15 +282,8 @@ func Test_addContainerLabels(t *testing.T) {
}
networkLabels := getNetworkLabelsByNetworkID(networks)
tests := []struct {
name string
c container
want []*promutils.Labels
wantErr bool
}{
{
name: "NetworkMode!=host",
c: container{
// NetworkMode != host
c := container{
ID: "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
Names: []string{"/crow-server"},
Labels: map[string]string{
@ -333,29 +294,19 @@ func Test_addContainerLabels(t *testing.T) {
"com.docker.compose.service": "crow-server",
"com.docker.compose.version": "1.11.2",
},
HostConfig: struct {
NetworkMode string
}{
HostConfig: containerHostConfig{
NetworkMode: "bridge",
},
NetworkSettings: struct {
Networks map[string]struct {
IPAddress string
NetworkID string
}
}{
Networks: map[string]struct {
IPAddress string
NetworkID string
}{
NetworkSettings: containerNetworkSettings{
Networks: map[string]containerNetwork{
"host": {
IPAddress: "172.17.0.2",
NetworkID: "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "172.17.0.2:8012",
"__meta_docker_container_id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
@ -374,11 +325,11 @@ func Test_addContainerLabels(t *testing.T) {
"__meta_docker_network_name": "bridge",
"__meta_docker_network_scope": "local",
}),
},
},
{
name: "NetworkMode=host",
c: container{
}
f(c, networkLabels, labelssExpected)
// NetworkMode=host
c = container{
ID: "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
Names: []string{"/crow-server"},
Labels: map[string]string{
@ -389,29 +340,19 @@ func Test_addContainerLabels(t *testing.T) {
"com.docker.compose.service": "crow-server",
"com.docker.compose.version": "1.11.2",
},
HostConfig: struct {
NetworkMode string
}{
HostConfig: containerHostConfig{
NetworkMode: "host",
},
NetworkSettings: struct {
Networks map[string]struct {
IPAddress string
NetworkID string
}
}{
Networks: map[string]struct {
IPAddress string
NetworkID string
}{
NetworkSettings: containerNetworkSettings{
Networks: map[string]containerNetwork{
"host": {
IPAddress: "172.17.0.2",
NetworkID: "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected = []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "foobar",
"__meta_docker_container_id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
@ -430,11 +371,11 @@ func Test_addContainerLabels(t *testing.T) {
"__meta_docker_network_name": "bridge",
"__meta_docker_network_scope": "local",
}),
},
},
{
name: "get labels from a container",
c: container{
}
f(c, networkLabels, labelssExpected)
// get labels from a container
c = container{
ID: "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
Names: []string{"/crow-server"},
Labels: map[string]string{
@ -445,40 +386,27 @@ func Test_addContainerLabels(t *testing.T) {
"com.docker.compose.service": "crow-server",
"com.docker.compose.version": "1.11.2",
},
Ports: []struct {
IP string
PrivatePort int
PublicPort int
Type string
}{{
Ports: []containerPort{
{
IP: "0.0.0.0",
PrivatePort: 8080,
PublicPort: 18081,
Type: "tcp",
}},
HostConfig: struct {
NetworkMode string
}{
},
},
HostConfig: containerHostConfig{
NetworkMode: "bridge",
},
NetworkSettings: struct {
Networks map[string]struct {
IPAddress string
NetworkID string
}
}{
Networks: map[string]struct {
IPAddress string
NetworkID string
}{
NetworkSettings: containerNetworkSettings{
Networks: map[string]containerNetwork{
"bridge": {
IPAddress: "172.17.0.2",
NetworkID: "1dd8d1a8bef59943345c7231d7ce8268333ff5a8c5b3c94881e6b4742b447634",
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected = []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "172.17.0.2:8080",
"__meta_docker_container_id": "90bc3b31aa13da5c0b11af2e228d54b38428a84e25d4e249ae9e9c95e51a0700",
@ -500,18 +428,6 @@ func Test_addContainerLabels(t *testing.T) {
"__meta_docker_port_public": "18081",
"__meta_docker_port_public_ip": "0.0.0.0",
}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
labelss := addContainersLabels([]container{tt.c}, networkLabels, 8012, "foobar")
if (err != nil) != tt.wantErr {
t.Errorf("addContainersLabels() error = %v, wantErr %v", err, tt.wantErr)
return
}
discoveryutils.TestEqualLabelss(t, labelss, tt.want)
})
}
f(c, networkLabels, labelssExpected)
}

View file

@ -9,19 +9,26 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_addNetworkLabels(t *testing.T) {
type args struct {
networks []network
func TestAddNetworkLabels(t *testing.T) {
f := func(networks []network, labelssExpected []*promutils.Labels) {
t.Helper()
networkLabels := getNetworkLabelsByNetworkID(networks)
var networkIDs []string
for networkID := range networkLabels {
networkIDs = append(networkIDs, networkID)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
{
name: "ingress network",
args: args{
networks: []network{
sort.Strings(networkIDs)
var labelss []*promutils.Labels
for _, networkID := range networkIDs {
labelss = append(labelss, networkLabels[networkID])
}
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
// ingress network
networks := []network{
{
ID: "qs0hog6ldlei9ct11pr3c77v1",
Ingress: true,
@ -31,9 +38,8 @@ func Test_addNetworkLabels(t *testing.T) {
"key1": "value1",
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__meta_docker_network_id": "qs0hog6ldlei9ct11pr3c77v1",
"__meta_docker_network_ingress": "true",
@ -41,40 +47,26 @@ func Test_addNetworkLabels(t *testing.T) {
"__meta_docker_network_label_key1": "value1",
"__meta_docker_network_name": "ingress",
"__meta_docker_network_scope": "swarm",
})},
},
}),
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := getNetworkLabelsByNetworkID(tt.args.networks)
var networkIDs []string
for networkID := range got {
networkIDs = append(networkIDs, networkID)
f(networks, labelssExpected)
}
sort.Strings(networkIDs)
var labelss []*promutils.Labels
for _, networkID := range networkIDs {
labelss = append(labelss, got[networkID])
func TestParseNetworks(t *testing.T) {
f := func(data string, resultExpected []network) {
t.Helper()
result, err := parseNetworks([]byte(data))
if err != nil {
t.Fatalf("parseNetworks() error: %s", err)
}
discoveryutils.TestEqualLabelss(t, labelss, tt.want)
})
if !reflect.DeepEqual(result, resultExpected) {
t.Fatalf("unexpected networks\ngot\n%v\nwant\n%v", result, resultExpected)
}
}
func Test_parseNetworks(t *testing.T) {
type args struct {
data []byte
}
tests := []struct {
name string
args args
want []network
wantErr bool
}{
{
name: "parse two networks",
args: args{
data: []byte(`[
// parse two networks
data := `[
{
"Name": "ingress",
"Id": "qs0hog6ldlei9ct11pr3c77v1",
@ -132,9 +124,8 @@ func Test_parseNetworks(t *testing.T) {
"key": "value"
}
}
]`),
},
want: []network{
]`
resultExpected := []network{
{
ID: "qs0hog6ldlei9ct11pr3c77v1",
Ingress: true,
@ -152,19 +143,6 @@ func Test_parseNetworks(t *testing.T) {
"key": "value",
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseNetworks(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("parseNetworks() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseNetworks() \ngot %v, \nwant %v", got, tt.want)
}
})
}
f(data, resultExpected)
}

View file

@ -9,19 +9,26 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_addNetworkLabels(t *testing.T) {
type args struct {
networks []network
func TestAddNetworkLabels(t *testing.T) {
f := func(networks []network, labelssExpected []*promutils.Labels) {
t.Helper()
networkLabels := getNetworkLabelsByNetworkID(networks)
var networkIDs []string
for networkID := range networkLabels {
networkIDs = append(networkIDs, networkID)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
{
name: "ingress network",
args: args{
networks: []network{
sort.Strings(networkIDs)
var labelss []*promutils.Labels
for _, networkID := range networkIDs {
labelss = append(labelss, networkLabels[networkID])
}
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
// ingress network
networks := []network{
{
ID: "qs0hog6ldlei9ct11pr3c77v1",
Ingress: true,
@ -31,9 +38,8 @@ func Test_addNetworkLabels(t *testing.T) {
"key1": "value1",
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__meta_dockerswarm_network_id": "qs0hog6ldlei9ct11pr3c77v1",
"__meta_dockerswarm_network_ingress": "true",
@ -41,40 +47,26 @@ func Test_addNetworkLabels(t *testing.T) {
"__meta_dockerswarm_network_label_key1": "value1",
"__meta_dockerswarm_network_name": "ingress",
"__meta_dockerswarm_network_scope": "swarm",
})},
},
}),
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := getNetworkLabelsByNetworkID(tt.args.networks)
var networkIDs []string
for networkID := range got {
networkIDs = append(networkIDs, networkID)
f(networks, labelssExpected)
}
sort.Strings(networkIDs)
var labelss []*promutils.Labels
for _, networkID := range networkIDs {
labelss = append(labelss, got[networkID])
func TestParseNetworks(t *testing.T) {
f := func(data string, resultExpected []network) {
t.Helper()
result, err := parseNetworks([]byte(data))
if err != nil {
t.Fatalf("parseNetworks() error: %s", err)
}
discoveryutils.TestEqualLabelss(t, labelss, tt.want)
})
if !reflect.DeepEqual(result, resultExpected) {
t.Fatalf("unexpected result\ngot\n%v\nwant\n%v", result, resultExpected)
}
}
func Test_parseNetworks(t *testing.T) {
type args struct {
data []byte
}
tests := []struct {
name string
args args
want []network
wantErr bool
}{
{
name: "parse two networks",
args: args{
data: []byte(`[
// parse two networks
data := `[
{
"Name": "ingress",
"Id": "qs0hog6ldlei9ct11pr3c77v1",
@ -132,9 +124,8 @@ func Test_parseNetworks(t *testing.T) {
"key": "value"
}
}
]`),
},
want: []network{
]`
resultExpected := []network{
{
ID: "qs0hog6ldlei9ct11pr3c77v1",
Ingress: true,
@ -152,19 +143,6 @@ func Test_parseNetworks(t *testing.T) {
"key": "value",
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseNetworks(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("parseNetworks() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseNetworks() \ngot %v, \nwant %v", got, tt.want)
}
})
}
f(data, resultExpected)
}

View file

@ -11,32 +11,44 @@ import (
// See https://docs.docker.com/engine/api/v1.40/#tag/Node
type node struct {
ID string
Spec struct {
Spec nodeSpec
Description nodeDescription
Status nodeStatus
ManagerStatus nodeManagerStatus
}
type nodeSpec struct {
Labels map[string]string
Role string
Availability string
}
Description struct {
type nodeDescription struct {
Hostname string
Platform struct {
Platform nodePlatform
Engine nodeEngine
}
type nodePlatform struct {
Architecture string
OS string
}
Engine struct {
type nodeEngine struct {
EngineVersion string
}
}
Status struct {
type nodeStatus struct {
State string
Message string
Addr string
}
ManagerStatus struct {
type nodeManagerStatus struct {
Leader bool
Reachability string
Addr string
}
}
func getNodesLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
nodes, err := getNodes(cfg)

View file

@ -8,20 +8,21 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_parseNodes(t *testing.T) {
type args struct {
data []byte
func TestParseNodes(t *testing.T) {
f := func(data string, resultExpected []node) {
t.Helper()
result, err := parseNodes([]byte(data))
if err != nil {
t.Fatalf("parseNodes() error: %s", err)
}
tests := []struct {
name string
args args
want []node
wantErr bool
}{
{
name: "parse ok",
args: args{
data: []byte(`[
if !reflect.DeepEqual(result, resultExpected) {
t.Fatalf("unexpected result;\ngot\n%v\nwant\n%v", result, resultExpected)
}
}
// parse ok
data := `[
{
"ID": "qauwmifceyvqs0sipvzu8oslu",
"Version": {
@ -51,110 +52,66 @@ func Test_parseNodes(t *testing.T) {
}
}
]
`),
},
want: []node{
`
resultExpected := []node{
{
ID: "qauwmifceyvqs0sipvzu8oslu",
Spec: struct {
Labels map[string]string
Role string
Availability string
}{Role: "manager", Availability: "active"},
Status: struct {
State string
Message string
Addr string
}{State: "ready", Addr: "172.31.40.97"},
Description: struct {
Hostname string
Platform struct {
Architecture string
OS string
}
Engine struct{ EngineVersion string }
}{
Spec: nodeSpec{
Role: "manager",
Availability: "active",
},
Status: nodeStatus{
State: "ready",
Addr: "172.31.40.97",
},
Description: nodeDescription{
Hostname: "ip-172-31-40-97",
Platform: struct {
Architecture string
OS string
}{
Platform: nodePlatform{
Architecture: "x86_64",
OS: "linux",
},
Engine: struct{ EngineVersion string }{
Engine: nodeEngine{
EngineVersion: "19.03.11",
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseNodes(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("parseNodes() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseNodes() \ngot %v, \nwant %v", got, tt.want)
}
})
}
f(data, resultExpected)
}
func Test_addNodeLabels(t *testing.T) {
type args struct {
nodes []node
port int
func TestAddNodeLabels(t *testing.T) {
f := func(nodes []node, port int, resultExpected []*promutils.Labels) {
t.Helper()
result := addNodeLabels(nodes, port)
discoveryutils.TestEqualLabelss(t, result, resultExpected)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
{
name: "add labels to one node",
args: args{
nodes: []node{
// add labels to one node
nodes := []node{
{
ID: "qauwmifceyvqs0sipvzu8oslu",
Spec: struct {
Labels map[string]string
Role string
Availability string
}{Role: "manager", Availability: "active"},
Status: struct {
State string
Message string
Addr string
}{State: "ready", Addr: "172.31.40.97"},
Description: struct {
Hostname string
Platform struct {
Architecture string
OS string
}
Engine struct{ EngineVersion string }
}{
Spec: nodeSpec{
Role: "manager",
Availability: "active",
},
Status: nodeStatus{
State: "ready",
Addr: "172.31.40.97",
},
Description: nodeDescription{
Hostname: "ip-172-31-40-97",
Platform: struct {
Architecture string
OS string
}{
Platform: nodePlatform{
Architecture: "x86_64",
OS: "linux",
},
Engine: struct{ EngineVersion string }{
Engine: nodeEngine{
EngineVersion: "19.03.11",
},
},
},
},
port: 9100,
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "172.31.40.97:9100",
"__meta_dockerswarm_node_address": "172.31.40.97",
@ -169,13 +126,7 @@ func Test_addNodeLabels(t *testing.T) {
"__meta_dockerswarm_node_platform_os": "linux",
"__meta_dockerswarm_node_role": "manager",
"__meta_dockerswarm_node_status": "ready",
})},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := addNodeLabels(tt.args.nodes, tt.args.port)
discoveryutils.TestEqualLabelss(t, got, tt.want)
})
}),
}
f(nodes, 9100, labelssExpected)
}

View file

@ -13,31 +13,45 @@ import (
// https://docs.docker.com/engine/api/v1.40/#tag/Service
type service struct {
ID string
Spec struct {
Spec serviceSpec
UpdateStatus serviceUpdateStatus
Endpoint serviceEndpoint
}
type serviceSpec struct {
Labels map[string]string
Name string
TaskTemplate struct {
ContainerSpec struct {
TaskTemplate taskTemplate
Mode serviceSpecMode
}
type taskTemplate struct {
ContainerSpec containerSpec
}
type containerSpec struct {
Hostname string
Image string
}
}
Mode struct {
type serviceSpecMode struct {
Global interface{}
Replicated interface{}
}
}
UpdateStatus struct {
type serviceUpdateStatus struct {
State string
}
Endpoint struct {
type serviceEndpoint struct {
Ports []portConfig
VirtualIPs []struct {
VirtualIPs []virtualIP
}
type virtualIP struct {
NetworkID string
Addr string
}
}
}
type portConfig struct {
Protocol string

View file

@ -8,20 +8,21 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_parseServicesResponse(t *testing.T) {
type args struct {
data []byte
func TestParseServicesResponse(t *testing.T) {
f := func(data string, servicesExpected []service) {
t.Helper()
services, err := parseServicesResponse([]byte(data))
if err != nil {
t.Fatalf("parseServicesResponse() error: %s", err)
}
tests := []struct {
name string
args args
want []service
wantErr bool
}{
{
name: "parse ok",
args: args{
data: []byte(`[
if !reflect.DeepEqual(services, servicesExpected) {
t.Fatalf("unexpected result\ngot\n%v\nwant\n%v", services, servicesExpected)
}
}
// parse ok
data := `[
{
"ID": "tgsci5gd31aai3jyudv98pqxf",
"Version": {
@ -87,64 +88,32 @@ func Test_parseServicesResponse(t *testing.T) {
]
}
}
]`),
},
want: []service{
]`
servicesExpected := []service{
{
ID: "tgsci5gd31aai3jyudv98pqxf",
Spec: struct {
Labels map[string]string
Name string
TaskTemplate struct {
ContainerSpec struct {
Hostname string
Image string
}
}
Mode struct {
Global interface{}
Replicated interface{}
}
}{
Spec: serviceSpec{
Labels: map[string]string{},
Name: "redis2",
TaskTemplate: struct {
ContainerSpec struct {
Hostname string
Image string
}
}{
ContainerSpec: struct {
Hostname string
Image string
}{
Hostname: "",
TaskTemplate: taskTemplate{
ContainerSpec: containerSpec{
Image: "redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842",
},
},
Mode: struct {
Global interface{}
Replicated interface{}
}{
Mode: serviceSpecMode{
Replicated: map[string]interface{}{},
},
},
Endpoint: struct {
Ports []portConfig
VirtualIPs []struct {
NetworkID string
Addr string
}
}{Ports: []portConfig{
Endpoint: serviceEndpoint{
Ports: []portConfig{
{
Protocol: "tcp",
PublishMode: "ingress",
PublishedPort: 8081,
},
}, VirtualIPs: []struct {
NetworkID string
Addr string
}{
},
VirtualIPs: []virtualIP{
{
NetworkID: "qs0hog6ldlei9ct11pr3c77v1",
Addr: "10.0.0.3/24",
@ -152,39 +121,53 @@ func Test_parseServicesResponse(t *testing.T) {
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseServicesResponse(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("parseServicesResponse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseServicesResponse() \ngot %v, \nwant %v", got, tt.want)
}
})
}
f(data, servicesExpected)
}
func Test_addServicesLabels(t *testing.T) {
type args struct {
services []service
networksLabels map[string]*promutils.Labels
port int
func TestAddServicesLabels(t *testing.T) {
f := func(services []service, networksLabels map[string]*promutils.Labels, labelssExpected []*promutils.Labels) {
t.Helper()
labelss := addServicesLabels(services, networksLabels, 9100)
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
// add 2 services with network labels join
services := []service{
{
name: "add 2 services with network labels join",
args: args{
port: 9100,
networksLabels: map[string]*promutils.Labels{
ID: "tgsci5gd31aai3jyudv98pqxf",
Spec: serviceSpec{
Labels: map[string]string{},
Name: "redis2",
TaskTemplate: taskTemplate{
ContainerSpec: containerSpec{
Hostname: "node1",
Image: "redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842",
},
},
Mode: serviceSpecMode{
Replicated: map[string]interface{}{},
},
},
Endpoint: serviceEndpoint{
Ports: []portConfig{
{
Protocol: "tcp",
Name: "redis",
PublishMode: "ingress",
},
},
VirtualIPs: []virtualIP{
{
NetworkID: "qs0hog6ldlei9ct11pr3c77v1",
Addr: "10.0.0.3/24",
},
},
},
},
}
networksLabels := map[string]*promutils.Labels{
"qs0hog6ldlei9ct11pr3c77v1": promutils.NewLabelsFromMap(map[string]string{
"__meta_dockerswarm_network_id": "qs0hog6ldlei9ct11pr3c77v1",
"__meta_dockerswarm_network_ingress": "true",
@ -193,73 +176,8 @@ func Test_addServicesLabels(t *testing.T) {
"__meta_dockerswarm_network_name": "ingress",
"__meta_dockerswarm_network_scope": "swarm",
}),
},
services: []service{
{
ID: "tgsci5gd31aai3jyudv98pqxf",
Spec: struct {
Labels map[string]string
Name string
TaskTemplate struct {
ContainerSpec struct {
Hostname string
Image string
}
}
Mode struct {
Global interface{}
Replicated interface{}
}
}{
Labels: map[string]string{},
Name: "redis2",
TaskTemplate: struct {
ContainerSpec struct {
Hostname string
Image string
}
}{
ContainerSpec: struct {
Hostname string
Image string
}{
Hostname: "node1",
Image: "redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842",
},
},
Mode: struct {
Global interface{}
Replicated interface{}
}{
Replicated: map[string]interface{}{},
},
},
Endpoint: struct {
Ports []portConfig
VirtualIPs []struct {
NetworkID string
Addr string
}
}{Ports: []portConfig{
{
Protocol: "tcp",
Name: "redis",
PublishMode: "ingress",
},
}, VirtualIPs: []struct {
NetworkID string
Addr string
}{
{
NetworkID: "qs0hog6ldlei9ct11pr3c77v1",
Addr: "10.0.0.3/24",
},
},
},
},
},
},
want: []*promutils.Labels{
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "10.0.0.3:0",
"__meta_dockerswarm_network_id": "qs0hog6ldlei9ct11pr3c77v1",
@ -276,13 +194,7 @@ func Test_addServicesLabels(t *testing.T) {
"__meta_dockerswarm_service_task_container_hostname": "node1",
"__meta_dockerswarm_service_task_container_image": "redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842",
"__meta_dockerswarm_service_updating_status": "",
})},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := addServicesLabels(tt.args.services, tt.args.networksLabels, tt.args.port)
discoveryutils.TestEqualLabelss(t, got, tt.want)
})
}),
}
f(services, networksLabels, labelssExpected)
}

View file

@ -17,28 +17,38 @@ type task struct {
ServiceID string
NodeID string
DesiredState string
NetworksAttachments []struct {
NetworksAttachments []networkAttachment
Status taskStatus
Spec taskSpec
Slot int
}
type networkAttachment struct {
Addresses []string
Network struct {
ID string
Network network
}
}
Status struct {
type taskStatus struct {
State string
ContainerStatus struct {
ContainerStatus containerStatus
PortStatus portStatus
}
type containerStatus struct {
ContainerID string
}
PortStatus struct {
type portStatus struct {
Ports []portConfig
}
type taskSpec struct {
ContainerSpec taskContainerSpec
}
Spec struct {
ContainerSpec struct {
type taskContainerSpec struct {
Labels map[string]string
}
}
Slot int
}
func getTasksLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
tasks, err := getTasks(cfg)

View file

@ -8,20 +8,21 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_parseTasks(t *testing.T) {
type args struct {
data []byte
func TestParseTasks(t *testing.T) {
f := func(data string, tasksExpected []task) {
t.Helper()
tasks, err := parseTasks([]byte(data))
if err != nil {
t.Fatalf("parseTasks() error: %s", err)
}
tests := []struct {
name string
args args
want []task
wantErr bool
}{
{
name: "parse ok",
args: args{
data: []byte(`[
if !reflect.DeepEqual(tasks, tasksExpected) {
t.Fatalf("unexpected result\ngot\n%v\nwant\n%v", tasks, tasksExpected)
}
}
// parse ok
data := `[
{
"ID": "t4rdm7j2y9yctbrksiwvsgpu5",
"Version": {
@ -63,21 +64,15 @@ func Test_parseTasks(t *testing.T) {
"DesiredState": "running"
}
]
`),
},
want: []task{
`
tasksExpected := []task{
{
ID: "t4rdm7j2y9yctbrksiwvsgpu5",
ServiceID: "t91nf284wzle1ya09lqvyjgnq",
NodeID: "qauwmifceyvqs0sipvzu8oslu",
Spec: struct {
ContainerSpec struct {
Labels map[string]string
}
}{
ContainerSpec: struct {
Labels map[string]string
}{
Spec: taskSpec{
ContainerSpec: taskContainerSpec{
Labels: map[string]string{
"label1": "value1",
},
@ -85,69 +80,40 @@ func Test_parseTasks(t *testing.T) {
},
DesiredState: "running",
Slot: 1,
Status: struct {
State string
ContainerStatus struct{ ContainerID string }
PortStatus struct{ Ports []portConfig }
}{
Status: taskStatus{
State: "running",
ContainerStatus: struct{ ContainerID string }{
ContainerStatus: containerStatus{
ContainerID: "33034b69f6fa5f808098208752fd1fe4e0e1ca86311988cea6a73b998cdc62e8",
},
PortStatus: struct{ Ports []portConfig }{}},
},
PortStatus: portStatus{},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseTasks(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("parseTasks() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseTasks() got\n%v\nwant\n%v", got, tt.want)
}
})
}
f(data, tasksExpected)
}
func Test_addTasksLabels(t *testing.T) {
type args struct {
tasks []task
nodesLabels []*promutils.Labels
servicesLabels []*promutils.Labels
networksLabels map[string]*promutils.Labels
services []service
port int
func TestAddTasksLabels(t *testing.T) {
f := func(tasks []task, nodesLabels []*promutils.Labels, networkLabels map[string]*promutils.Labels, services []service, labelssExpected []*promutils.Labels) {
t.Helper()
labelss := addTasksLabels(tasks, nodesLabels, nil, networkLabels, services, 9100)
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
{
name: "adds 1 task with nodes labels",
args: args{
port: 9100,
tasks: []task{
// adds 1 task with nodes labels
tasks := []task{
{
ID: "t4rdm7j2y9yctbrksiwvsgpu5",
ServiceID: "t91nf284wzle1ya09lqvyjgnq",
NodeID: "qauwmifceyvqs0sipvzu8oslu",
DesiredState: "running",
Slot: 1,
Status: struct {
State string
ContainerStatus struct{ ContainerID string }
PortStatus struct{ Ports []portConfig }
}{
Status: taskStatus{
State: "running",
ContainerStatus: struct{ ContainerID string }{
ContainerStatus: containerStatus{
ContainerID: "33034b69f6fa5f808098208752fd1fe4e0e1ca86311988cea6a73b998cdc62e8",
},
PortStatus: struct{ Ports []portConfig }{
PortStatus: portStatus{
Ports: []portConfig{
{
PublishMode: "ingress",
@ -158,8 +124,9 @@ func Test_addTasksLabels(t *testing.T) {
},
}},
},
},
nodesLabels: []*promutils.Labels{
}
nodesLabels := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "172.31.40.97:9100",
"__meta_dockerswarm_node_address": "172.31.40.97",
@ -172,9 +139,9 @@ func Test_addTasksLabels(t *testing.T) {
"__meta_dockerswarm_node_role": "manager",
"__meta_dockerswarm_node_status": "ready",
}),
},
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "172.31.40.97:6379",
"__meta_dockerswarm_node_address": "172.31.40.97",
@ -192,45 +159,37 @@ func Test_addTasksLabels(t *testing.T) {
"__meta_dockerswarm_task_port_publish_mode": "ingress",
"__meta_dockerswarm_task_slot": "1",
"__meta_dockerswarm_task_state": "running",
})},
},
{
name: "adds 1 task with nodes, network and services labels",
args: args{
port: 9100,
tasks: []task{
}),
}
f(tasks, nodesLabels, nil, nil, labelssExpected)
// adds 1 task with nodes, network and services labels
tasks = []task{
{
ID: "t4rdm7j2y9yctbrksiwvsgpu5",
ServiceID: "tgsci5gd31aai3jyudv98pqxf",
NodeID: "qauwmifceyvqs0sipvzu8oslu",
DesiredState: "running",
Slot: 1,
NetworksAttachments: []struct {
Addresses []string
Network struct{ ID string }
}{
NetworksAttachments: []networkAttachment{
{
Network: struct {
ID string
}{
Network: network{
ID: "qs0hog6ldlei9ct11pr3c77v1",
},
Addresses: []string{"10.10.15.15/24"},
},
},
Status: struct {
State string
ContainerStatus struct{ ContainerID string }
PortStatus struct{ Ports []portConfig }
}{
Status: taskStatus{
State: "running",
ContainerStatus: struct{ ContainerID string }{
ContainerStatus: containerStatus{
ContainerID: "33034b69f6fa5f808098208752fd1fe4e0e1ca86311988cea6a73b998cdc62e8",
},
PortStatus: struct{ Ports []portConfig }{}},
PortStatus: portStatus{},
},
},
networksLabels: map[string]*promutils.Labels{
}
networksLabels := map[string]*promutils.Labels{
"qs0hog6ldlei9ct11pr3c77v1": promutils.NewLabelsFromMap(map[string]string{
"__meta_dockerswarm_network_id": "qs0hog6ldlei9ct11pr3c77v1",
"__meta_dockerswarm_network_ingress": "true",
@ -239,8 +198,9 @@ func Test_addTasksLabels(t *testing.T) {
"__meta_dockerswarm_network_name": "ingress",
"__meta_dockerswarm_network_scope": "swarm",
}),
},
nodesLabels: []*promutils.Labels{
}
nodesLabels = []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "172.31.40.97:9100",
"__meta_dockerswarm_node_address": "172.31.40.97",
@ -253,54 +213,25 @@ func Test_addTasksLabels(t *testing.T) {
"__meta_dockerswarm_node_role": "manager",
"__meta_dockerswarm_node_status": "ready",
}),
},
services: []service{
}
services := []service{
{
ID: "tgsci5gd31aai3jyudv98pqxf",
Spec: struct {
Labels map[string]string
Name string
TaskTemplate struct {
ContainerSpec struct {
Hostname string
Image string
}
}
Mode struct {
Global interface{}
Replicated interface{}
}
}{
Spec: serviceSpec{
Labels: map[string]string{},
Name: "redis2",
TaskTemplate: struct {
ContainerSpec struct {
Hostname string
Image string
}
}{
ContainerSpec: struct {
Hostname string
Image string
}{
TaskTemplate: taskTemplate{
ContainerSpec: containerSpec{
Hostname: "node1",
Image: "redis:3.0.6@sha256:6a692a76c2081888b589e26e6ec835743119fe453d67ecf03df7de5b73d69842",
},
},
Mode: struct {
Global interface{}
Replicated interface{}
}{
Mode: serviceSpecMode{
Replicated: map[string]interface{}{},
},
},
Endpoint: struct {
Ports []portConfig
VirtualIPs []struct {
NetworkID string
Addr string
}
}{
Endpoint: serviceEndpoint{
Ports: []portConfig{
{
Protocol: "tcp",
@ -308,10 +239,8 @@ func Test_addTasksLabels(t *testing.T) {
PublishMode: "ingress",
PublishedPort: 6379,
},
}, VirtualIPs: []struct {
NetworkID string
Addr string
}{
},
VirtualIPs: []virtualIP{
{
NetworkID: "qs0hog6ldlei9ct11pr3c77v1",
Addr: "10.0.0.3/24",
@ -319,10 +248,9 @@ func Test_addTasksLabels(t *testing.T) {
},
},
},
},
servicesLabels: []*promutils.Labels{},
},
want: []*promutils.Labels{
}
labelssExpected = []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "10.10.15.15:6379",
"__meta_dockerswarm_network_id": "qs0hog6ldlei9ct11pr3c77v1",
@ -347,13 +275,6 @@ func Test_addTasksLabels(t *testing.T) {
"__meta_dockerswarm_task_slot": "1",
"__meta_dockerswarm_task_state": "running",
}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := addTasksLabels(tt.args.tasks, tt.args.nodesLabels, tt.args.servicesLabels, tt.args.networksLabels, tt.args.services, tt.args.port)
discoveryutils.TestEqualLabelss(t, got, tt.want)
})
}
f(tasks, nodesLabels, networksLabels, services, labelssExpected)
}

View file

@ -5,20 +5,21 @@ import (
"testing"
)
func Test_parseAPIResponse(t *testing.T) {
type args struct {
data []byte
func TestParseAPIResponse(t *testing.T) {
f := func(data string, resultExpected *applications) {
t.Helper()
result, err := parseAPIResponse([]byte(data))
if err != nil {
t.Fatalf("parseAPIResponse() error: %s", err)
}
tests := []struct {
name string
args args
want *applications
wantErr bool
}{
{
name: "parse ok 1 app with instance",
args: args{
data: []byte(`<applications>
if !reflect.DeepEqual(result, resultExpected) {
t.Fatalf("unexpected result\ngot\n%v\nwant\n%v", result, resultExpected)
}
}
// parse ok 1 app with instance
data := `<applications>
<versions__delta>1</versions__delta>
<apps__hashcode>UP_1_</apps__hashcode>
<application>
@ -55,9 +56,9 @@ func Test_parseAPIResponse(t *testing.T) {
<actionType>ADDED</actionType>
</instance>
</application>
</applications>`),
},
want: &applications{
</applications>`
resultExpected := &applications{
Applications: []Application{
{
Name: "HELLO-NETFLIX-OSS",
@ -89,19 +90,6 @@ func Test_parseAPIResponse(t *testing.T) {
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseAPIResponse(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("parseAPIResponse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("unxpected response for parseAPIResponse() \ngot = %v, \nwant %v", got, tt.want)
}
})
}
f(data, resultExpected)
}

View file

@ -7,19 +7,16 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_addInstanceLabels(t *testing.T) {
type args struct {
applications *applications
func TestAddInstanceLabels(t *testing.T) {
f := func(applications *applications, labelssExpected []*promutils.Labels) {
t.Helper()
labelss := addInstanceLabels(applications)
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
{
name: "1 application",
args: args{
applications: &applications{
// one application
applications := &applications{
Applications: []Application{
{
Name: "test-app",
@ -34,12 +31,14 @@ func Test_addInstanceLabels(t *testing.T) {
CountryID: 5,
VipAddress: "10.15.11.11",
InstanceID: "some-id",
Metadata: MetaData{Items: []Tag{
Metadata: MetaData{
Items: []Tag{
{
Content: "value-1",
XMLName: struct{ Space, Local string }{Local: "key-1"},
},
}},
},
},
Port: Port{
Port: 9100,
},
@ -47,9 +46,8 @@ func Test_addInstanceLabels(t *testing.T) {
},
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "host-1:9100",
"instance": "some-id",
@ -68,13 +66,6 @@ func Test_addInstanceLabels(t *testing.T) {
"__meta_eureka_app_instance_port_enabled": "false",
"__meta_eureka_app_instance_status": "Ok",
}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := addInstanceLabels(tt.args.applications)
discoveryutils.TestEqualLabelss(t, got, tt.want)
})
}
f(applications, labelssExpected)
}

View file

@ -7,45 +7,30 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_parseAPIResponse(t *testing.T) {
type args struct {
data []byte
path string
}
tests := []struct {
name string
args args
want []httpGroupTarget
wantErr bool
}{
func TestParseAPIResponse(t *testing.T) {
f := func(data, path string, resultExpected []httpGroupTarget) {
t.Helper()
{
name: "parse ok",
args: args{
path: "/ok",
data: []byte(`[
result, err := parseAPIResponse([]byte(data), path)
if err != nil {
t.Fatalf("parseAPIResponse() error: %s", err)
}
if !reflect.DeepEqual(result, resultExpected) {
t.Fatalf("unexpected result\ngot\n%v\nwant\n%v", result, resultExpected)
}
}
// parse ok
data := `[
{"targets": ["http://target-1:9100","http://target-2:9150"],
"labels": {"label-1":"value-1"} }
]`),
},
want: []httpGroupTarget{
]`
path := "/ok"
resultExpected := []httpGroupTarget{
{
Labels: promutils.NewLabelsFromMap(map[string]string{"label-1": "value-1"}),
Targets: []string{"http://target-1:9100", "http://target-2:9150"},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseAPIResponse(tt.args.data, tt.args.path)
if (err != nil) != tt.wantErr {
t.Errorf("parseAPIResponse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseAPIResponse() got = %v, want %v", got, tt.want)
}
})
}
f(data, path, resultExpected)
}

View file

@ -7,26 +7,22 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_addHTTPTargetLabels(t *testing.T) {
type args struct {
src []httpGroupTarget
func TestAddHTTPTargetLabels(t *testing.T) {
f := func(src []httpGroupTarget, labelssExpected []*promutils.Labels) {
t.Helper()
labelss := addHTTPTargetLabels(src, "http://foo.bar/baz?aaa=bb")
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
{
name: "add ok",
args: args{
src: []httpGroupTarget{
// add ok
src := []httpGroupTarget{
{
Targets: []string{"127.0.0.1:9100", "127.0.0.2:91001"},
Labels: promutils.NewLabelsFromMap(map[string]string{"__meta_kubernetes_pod": "pod-1", "__meta_consul_dc": "dc-2"}),
},
},
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "127.0.0.1:9100",
"__meta_kubernetes_pod": "pod-1",
@ -39,13 +35,6 @@ func Test_addHTTPTargetLabels(t *testing.T) {
"__meta_consul_dc": "dc-2",
"__meta_url": "http://foo.bar/baz?aaa=bb",
}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := addHTTPTargetLabels(tt.args.src, "http://foo.bar/baz?aaa=bb")
discoveryutils.TestEqualLabelss(t, got, tt.want)
})
}
f(src, labelssExpected)
}

View file

@ -936,9 +936,12 @@ func (uw *urlWatcher) maybeUpdateDependedScrapeWorksLocked() {
// Bookmark is a bookmark message from Kubernetes Watch API.
// See https://kubernetes.io/docs/reference/using-api/api-concepts/#watch-bookmarks
type Bookmark struct {
Metadata struct {
ResourceVersion string
Metadata BookmarkMetadata
}
// BookmarkMetadata is metadata for Bookmark
type BookmarkMetadata struct {
ResourceVersion string
}
func parseBookmark(data []byte) (*Bookmark, error) {

View file

@ -12,10 +12,10 @@ func TestParseEndpointSliceListFail(t *testing.T) {
r := bytes.NewBufferString(data)
objectsByKey, _, err := parseEndpointSliceList(r)
if err == nil {
t.Errorf("unexpected result, test must fail! data: %s", data)
t.Fatalf("unexpected result, test must fail! data: %s", data)
}
if len(objectsByKey) != 0 {
t.Errorf("EndpointSliceList must be emptry, got: %v", objectsByKey)
t.Fatalf("EndpointSliceList must be emptry, got: %v", objectsByKey)
}
}
@ -156,8 +156,7 @@ func TestParseEndpointSliceListSuccess(t *testing.T) {
r := bytes.NewBufferString(data)
objectsByKey, meta, err := parseEndpointSliceList(r)
if err != nil {
t.Errorf("cannot parse data for EndpointSliceList: %v", err)
return
t.Fatalf("cannot parse data for EndpointSliceList: %v", err)
}
expectedResourceVersion := "1177"
if meta.ResourceVersion != expectedResourceVersion {

View file

@ -22,19 +22,25 @@ type apiConfig struct {
type Config struct {
Kind string `yaml:"kind,omitempty"`
APIVersion string `yaml:"apiVersion,omitempty"`
Clusters []struct {
Clusters []configCluster `yaml:"clusters"`
AuthInfos []authInfo `yaml:"users"`
Contexts []configContext `yaml:"contexts"`
CurrentContext string `yaml:"current-context"`
}
type configCluster struct {
Name string `yaml:"name"`
Cluster *Cluster `yaml:"cluster"`
} `yaml:"clusters"`
AuthInfos []struct {
}
type authInfo struct {
Name string `yaml:"name"`
AuthInfo *AuthInfo `yaml:"user"`
} `yaml:"users"`
Contexts []struct {
}
type configContext struct {
Name string `yaml:"name"`
Context *Context `yaml:"context"`
} `yaml:"contexts"`
CurrentContext string `yaml:"current-context"`
}
// Cluster contains information about how to communicate with a kubernetes cluster

View file

@ -265,17 +265,21 @@ type discoveryRequestNode struct {
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/discovery/v3/discovery.proto#envoy-v3-api-msg-service-discovery-v3-discoveryresponse
type discoveryResponse struct {
VersionInfo string `json:"version_info"`
Resources []struct {
Resources []resource `json:"resources"`
Nonce string `json:"nonce"`
}
type resource struct {
Mesh string `json:"mesh"`
Service string `json:"service"`
Targets []struct {
Targets []target `json:"targets"`
Labels map[string]string `json:"labels"`
}
type target struct {
Name string `json:"name"`
Scheme string `json:"scheme"`
Address string `json:"address"`
MetricsPath string `json:"metrics_path"`
Labels map[string]string `json:"labels"`
} `json:"targets"`
Labels map[string]string `json:"labels"`
} `json:"resources"`
Nonce string `json:"nonce"`
}

View file

@ -25,10 +25,12 @@ func getServiceLabels(cfg *apiConfig) []*promutils.Labels {
// See https://developer.hashicorp.com/nomad/api-docs/services#list-services
type ServiceList struct {
Namespace string `json:"Namespace"`
Services []struct {
Services []service `json:"Services"`
}
type service struct {
ServiceName string `json:"ServiceName"`
Tags []string `json:"Tags"`
} `json:"Services"`
}
// Service is Nomad service.

View file

@ -14,11 +14,13 @@ import (
//
// See https://docs.openstack.org/api-ref/identity/v3/#authentication-and-token-management
type authResponse struct {
Token struct {
Token authToken
}
type authToken struct {
ExpiresAt time.Time `json:"expires_at,omitempty"`
Catalog []catalogItem `json:"catalog,omitempty"`
}
}
type catalogItem struct {
Name string `json:"name"`

View file

@ -1,94 +1,88 @@
package openstack
import (
"reflect"
"testing"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promauth"
)
func Test_buildAuthRequestBody1(t *testing.T) {
type args struct {
sdc *SDConfig
}
tests := []struct {
name string
args args
want []byte
wantErr bool
}{
{
name: "empty config",
args: args{
sdc: &SDConfig{},
},
wantErr: true,
},
{
name: "username password auth with domain",
args: args{
sdc: &SDConfig{
Username: "some-user",
Password: promauth.NewSecret("some-password"),
DomainName: "some-domain",
},
},
want: []byte(`{"auth":{"identity":{"methods":["password"],"password":{"user":{"name":"some-user","password":"some-password","domain":{"name":"some-domain"}}}},"scope":{"domain":{"name":"some-domain"}}}}`),
},
{
name: "application credentials auth",
args: args{
sdc: &SDConfig{
ApplicationCredentialID: "some-id",
ApplicationCredentialSecret: promauth.NewSecret("some-secret"),
},
},
want: []byte(`{"auth":{"identity":{"methods":["application_credential"],"application_credential":{"id":"some-id","secret":"some-secret"}}}}`),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := buildAuthRequestBody(tt.args.sdc)
if (err != nil) != tt.wantErr {
t.Errorf("buildAuthRequestBody() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("buildAuthRequestBody() got = %v, want %v", got, tt.want)
}
})
func TestBuildAuthRequestBody_Failure(t *testing.T) {
f := func(sdc *SDConfig) {
t.Helper()
_, err := buildAuthRequestBody(sdc)
if err == nil {
t.Fatalf("expecting non-nil error")
}
}
func Test_getComputeEndpointURL1(t *testing.T) {
type args struct {
catalog []catalogItem
availability string
region string
// empty config
f(&SDConfig{})
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{
name: "bad catalog data",
args: args{
catalog: []catalogItem{
func TestBuildAuthRequestBody_Success(t *testing.T) {
f := func(sdc *SDConfig, resultExpected string) {
t.Helper()
result, err := buildAuthRequestBody(sdc)
if err != nil {
t.Fatalf("buildAuthRequestBody() error: %s", err)
}
if string(result) != resultExpected {
t.Fatalf("unexpected result\ngot\n%s\nwant\n%s", result, resultExpected)
}
}
// username password auth with domain
f(&SDConfig{
Username: "some-user",
Password: promauth.NewSecret("some-password"),
DomainName: "some-domain",
}, `{"auth":{"identity":{"methods":["password"],"password":{"user":{"name":"some-user","password":"some-password","domain":{"name":"some-domain"}}}},"scope":{"domain":{"name":"some-domain"}}}}`)
// application credentials auth
f(&SDConfig{
ApplicationCredentialID: "some-id",
ApplicationCredentialSecret: promauth.NewSecret("some-secret"),
}, `{"auth":{"identity":{"methods":["application_credential"],"application_credential":{"id":"some-id","secret":"some-secret"}}}}`)
}
func TestGetComputeEndpointURL_Failure(t *testing.T) {
f := func(catalog []catalogItem) {
t.Helper()
_, err := getComputeEndpointURL(catalog, "", "")
if err == nil {
t.Fatalf("expecting non-nil error")
}
}
// bad catalog data
catalog := []catalogItem{
{
Type: "keystone",
Endpoints: []endpoint{},
},
},
},
wantErr: true,
},
{
name: "good private url",
args: args{
availability: "private",
catalog: []catalogItem{
}
f(catalog)
}
func TestGetComputeEndpointURL_Success(t *testing.T) {
f := func(catalog []catalogItem, availability, region, resultExpected string) {
t.Helper()
resultURL, err := getComputeEndpointURL(catalog, availability, region)
if err != nil {
t.Fatalf("getComputeEndpointURL() error: %s", err)
}
if resultURL.String() != resultExpected {
t.Fatalf("unexpected result\ngot\n%s\nwant\n%s", resultURL, resultExpected)
}
}
// good private url
catalog := []catalogItem{
{
Type: "compute",
Endpoints: []endpoint{
@ -103,22 +97,8 @@ func Test_getComputeEndpointURL1(t *testing.T) {
Type: "keystone",
Endpoints: []endpoint{},
},
},
},
want: "https://compute.test.local:8083/v2.1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := getComputeEndpointURL(tt.args.catalog, tt.args.availability, tt.args.region)
if (err != nil) != tt.wantErr {
t.Errorf("getComputeEndpointURL() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && !reflect.DeepEqual(got.String(), tt.want) {
t.Errorf("getComputeEndpointURL() got = %v, want %v", got.String(), tt.want)
}
})
}
availability := "private"
resultExpected := "https://compute.test.local:8083/v2.1"
f(catalog, availability, "", resultExpected)
}

View file

@ -13,10 +13,12 @@ import (
// See https://docs.openstack.org/api-ref/compute/#list-hypervisors-details
type hypervisorDetail struct {
Hypervisors []hypervisor `json:"hypervisors"`
Links []struct {
Links []hypervisorLink `json:"hypervisors_links,omitempty"`
}
type hypervisorLink struct {
HREF string `json:"href"`
Rel string `json:"rel,omitempty"`
} `json:"hypervisors_links,omitempty"`
}
type hypervisor struct {

View file

@ -8,27 +8,35 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_parseHypervisorDetail(t *testing.T) {
type args struct {
data []byte
func TestParseHypervisorDetail_Failure(t *testing.T) {
f := func(data string) {
t.Helper()
_, err := parseHypervisorDetail([]byte(data))
if err == nil {
t.Fatalf("expecting non-nil error")
}
tests := []struct {
name string
args args
want hypervisorDetail
wantErr bool
}{
{
name: "bad data",
args: args{
data: []byte(`{ff}`),
},
wantErr: true,
},
{
name: "1 hypervisor",
args: args{
data: []byte(`{
}
// bad data
f(`{ff}`)
}
func TestParseHypervisorDetail_Success(t *testing.T) {
f := func(data string, resultExpected *hypervisorDetail) {
t.Helper()
result, err := parseHypervisorDetail([]byte(data))
if err != nil {
t.Fatalf("parseHypervisorDetail() error: %s", err)
}
if !reflect.DeepEqual(result, resultExpected) {
t.Fatalf("unexpected result\ngot\n%#v\nwant\n%#v", result, resultExpected)
}
}
// 1 hypervisor
data := `{
"hypervisors": [
{
"cpu_info": {
@ -69,9 +77,9 @@ func Test_parseHypervisorDetail(t *testing.T) {
"vcpus": 2,
"vcpus_used": 0
}
]}`),
},
want: hypervisorDetail{
]}`
resultExpected := &hypervisorDetail{
Hypervisors: []hypervisor{
{
HostIP: "1.1.1.1",
@ -82,38 +90,19 @@ func Test_parseHypervisorDetail(t *testing.T) {
Type: "fake",
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseHypervisorDetail(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("parseHypervisorDetail() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && !reflect.DeepEqual(*got, tt.want) {
t.Errorf("parseHypervisorDetail() got = %v, want %v", *got, tt.want)
}
})
}
f(data, resultExpected)
}
func Test_addHypervisorLabels(t *testing.T) {
type args struct {
hvs []hypervisor
port int
func TestAddHypervisorLabels(t *testing.T) {
f := func(hvs []hypervisor, labelssExpected []*promutils.Labels) {
t.Helper()
labelss := addHypervisorLabels(hvs, 9100)
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
{
name: "",
args: args{
port: 9100,
hvs: []hypervisor{
hvs := []hypervisor{
{
Type: "fake",
ID: 5,
@ -122,9 +111,8 @@ func Test_addHypervisorLabels(t *testing.T) {
Hostname: "fakehost",
HostIP: "1.2.2.2",
},
},
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "1.2.2.2:9100",
"__meta_openstack_hypervisor_host_ip": "1.2.2.2",
@ -134,13 +122,6 @@ func Test_addHypervisorLabels(t *testing.T) {
"__meta_openstack_hypervisor_status": "up",
"__meta_openstack_hypervisor_type": "fake",
}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := addHypervisorLabels(tt.args.hvs, tt.args.port)
discoveryutils.TestEqualLabelss(t, got, tt.want)
})
}
f(hvs, labelssExpected)
}

View file

@ -14,10 +14,12 @@ import (
// See https://docs.openstack.org/api-ref/compute/#list-servers
type serversDetail struct {
Servers []server `json:"servers"`
Links []struct {
Links []link `json:"servers_links,omitempty"`
}
type link struct {
HREF string `json:"href"`
Rel string `json:"rel"`
} `json:"servers_links,omitempty"`
}
type server struct {
@ -27,15 +29,19 @@ type server struct {
Name string `json:"name"`
HostID string `json:"hostid"`
Status string `json:"status"`
Addresses map[string][]struct {
Addresses map[string][]serverAddress `json:"addresses"`
Metadata map[string]string `json:"metadata,omitempty"`
Flavor serverFlavor `json:"flavor"`
}
type serverAddress struct {
Address string `json:"addr"`
Version int `json:"version"`
Type string `json:"OS-EXT-IPS:type"`
} `json:"addresses"`
Metadata map[string]string `json:"metadata,omitempty"`
Flavor struct {
}
type serverFlavor struct {
ID string `json:"id"`
} `json:"flavor"`
}
func parseServersDetail(data []byte) (*serversDetail, error) {

View file

@ -8,27 +8,19 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_addInstanceLabels(t *testing.T) {
type args struct {
servers []server
port int
func TestAddInstanceLabels(t *testing.T) {
f := func(servers []server, labelssExpected []*promutils.Labels) {
t.Helper()
labelss := addInstanceLabels(servers, 9100)
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
{
name: "empty_response",
args: args{
port: 9100,
},
},
{
name: "one_server",
args: args{
port: 9100,
servers: []server{
// empty response
f(nil, nil)
// one server
servers := []server{
{
ID: "10",
Status: "enabled",
@ -36,14 +28,10 @@ func Test_addInstanceLabels(t *testing.T) {
HostID: "some-host-id",
TenantID: "some-tenant-id",
UserID: "some-user-id",
Flavor: struct {
ID string `json:"id"`
}{ID: "5"},
Addresses: map[string][]struct {
Address string `json:"addr"`
Version int `json:"version"`
Type string `json:"OS-EXT-IPS:type"`
}{
Flavor: serverFlavor{
ID: "5",
},
Addresses: map[string][]serverAddress{
"test": {
{
Address: "192.168.0.1",
@ -53,9 +41,8 @@ func Test_addInstanceLabels(t *testing.T) {
},
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "192.168.0.1:9100",
"__meta_openstack_address_pool": "test",
@ -67,13 +54,11 @@ func Test_addInstanceLabels(t *testing.T) {
"__meta_openstack_project_id": "some-tenant-id",
"__meta_openstack_user_id": "some-user-id",
}),
},
},
{
name: "with_public_ip",
args: args{
port: 9100,
servers: []server{
}
f(servers, labelssExpected)
// with public ip
servers = []server{
{
ID: "10",
Status: "enabled",
@ -81,14 +66,10 @@ func Test_addInstanceLabels(t *testing.T) {
HostID: "some-host-id",
TenantID: "some-tenant-id",
UserID: "some-user-id",
Flavor: struct {
ID string `json:"id"`
}{ID: "5"},
Addresses: map[string][]struct {
Address string `json:"addr"`
Version int `json:"version"`
Type string `json:"OS-EXT-IPS:type"`
}{
Flavor: serverFlavor{
ID: "5",
},
Addresses: map[string][]serverAddress{
"test": {
{
Address: "192.168.0.1",
@ -110,9 +91,8 @@ func Test_addInstanceLabels(t *testing.T) {
},
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected = []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "10.10.0.1:9100",
"__meta_openstack_address_pool": "internal",
@ -136,31 +116,25 @@ func Test_addInstanceLabels(t *testing.T) {
"__meta_openstack_project_id": "some-tenant-id",
"__meta_openstack_user_id": "some-user-id",
}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := addInstanceLabels(tt.args.servers, tt.args.port)
discoveryutils.TestEqualLabelss(t, got, tt.want)
})
f(servers, labelssExpected)
}
func TestParseServersDetail(t *testing.T) {
f := func(data string, resultExpected *serversDetail) {
t.Helper()
result, err := parseServersDetail([]byte(data))
if err != nil {
t.Fatalf("parseServersDetail() error: %s", err)
}
if !reflect.DeepEqual(result, resultExpected) {
t.Fatalf("unexpected result\ngot\n%v\nwant\n%v", result, resultExpected)
}
}
func Test_parseServersDetail(t *testing.T) {
type args struct {
data []byte
}
tests := []struct {
name string
args args
want serversDetail
wantErr bool
}{
{
name: "parse ok",
args: args{
data: []byte(`{
// parse ok
data := `{
"servers":[
{
"id":"c9f68076-01a3-489a-aebe-8b773c71e7f3",
@ -210,14 +184,13 @@ func Test_parseServersDetail(t *testing.T) {
]
}
]
}`),
},
want: serversDetail{
}`
resultExpected := &serversDetail{
Servers: []server{
{
Flavor: struct {
ID string `json:"id"`
}{ID: "1"},
Flavor: serverFlavor{
ID: "1",
},
ID: "c9f68076-01a3-489a-aebe-8b773c71e7f3",
TenantID: "d34be4e44f9c444eab9a5ec7b953951f",
UserID: "e55737f142ac42f18093037760656bd7",
@ -225,11 +198,7 @@ func Test_parseServersDetail(t *testing.T) {
HostID: "e26db8db23736877aa92ebbbe11743b2a2a3b107aada00a8a0cf474b",
Status: "ACTIVE",
Metadata: map[string]string{},
Addresses: map[string][]struct {
Address string `json:"addr"`
Version int `json:"version"`
Type string `json:"OS-EXT-IPS:type"`
}{
Addresses: map[string][]serverAddress{
"test": {
{
Address: "192.168.222.15",
@ -245,19 +214,6 @@ func Test_parseServersDetail(t *testing.T) {
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseServersDetail(tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("parseServersDetail() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && !reflect.DeepEqual(*got, tt.want) {
t.Errorf("parseServersDetail() \ngot = %v,\nwant= %v", *got, tt.want)
}
})
}
f(data, resultExpected)
}

View file

@ -7,23 +7,19 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
func Test_addInstanceLabels(t *testing.T) {
type args struct {
instances []instance
func TestAddInstanceLabels(t *testing.T) {
f := func(instances []instance, labelssExpected []*promutils.Labels) {
t.Helper()
labelss := addInstanceLabels(instances)
discoveryutils.TestEqualLabelss(t, labelss, labelssExpected)
}
tests := []struct {
name string
args args
want []*promutils.Labels
}{
{
name: "empty_response",
args: args{},
},
{
name: "one_server",
args: args{
instances: []instance{
// empty response
f(nil, nil)
// one server
instances := []instance{
{
Name: "server-1",
ID: "test",
@ -45,9 +41,8 @@ func Test_addInstanceLabels(t *testing.T) {
},
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected := []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "server-1.ru-central1.internal",
"__meta_yandexcloud_instance_name": "server-1",
@ -61,12 +56,11 @@ func Test_addInstanceLabels(t *testing.T) {
"__meta_yandexcloud_folder_id": "test",
"__meta_yandexcloud_instance_private_ip_0": "192.168.1.1",
}),
},
},
{
name: "with_public_ip",
args: args{
instances: []instance{
}
f(instances, labelssExpected)
// with public ip
instances = []instance{
{
Name: "server-1",
ID: "test",
@ -91,9 +85,8 @@ func Test_addInstanceLabels(t *testing.T) {
},
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected = []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "server-1.ru-central1.internal",
"__meta_yandexcloud_instance_fqdn": "server-1.ru-central1.internal",
@ -108,12 +101,11 @@ func Test_addInstanceLabels(t *testing.T) {
"__meta_yandexcloud_instance_private_ip_0": "192.168.1.1",
"__meta_yandexcloud_instance_public_ip_0": "1.1.1.1",
}),
},
},
{
name: "with_dns_record",
args: args{
instances: []instance{
}
f(instances, labelssExpected)
// with dns record
instances = []instance{
{
Name: "server-1",
ID: "test",
@ -134,19 +126,22 @@ func Test_addInstanceLabels(t *testing.T) {
OneToOneNat: oneToOneNat{
Address: "1.1.1.1",
DNSRecords: []dnsRecord{
{FQDN: "server-1.example.com"},
{
FQDN: "server-1.example.com",
},
},
},
DNSRecords: []dnsRecord{
{FQDN: "server-1.example.local"},
{
FQDN: "server-1.example.local",
},
},
},
},
},
},
},
want: []*promutils.Labels{
}
labelssExpected = []*promutils.Labels{
promutils.NewLabelsFromMap(map[string]string{
"__address__": "server-1.ru-central1.internal",
"__meta_yandexcloud_instance_name": "server-1",
@ -163,13 +158,6 @@ func Test_addInstanceLabels(t *testing.T) {
"__meta_yandexcloud_instance_private_dns_0": "server-1.example.local",
"__meta_yandexcloud_instance_public_dns_0": "server-1.example.com",
}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := addInstanceLabels(tt.args.instances)
discoveryutils.TestEqualLabelss(t, got, tt.want)
})
}
f(instances, labelssExpected)
}

View file

@ -19,18 +19,40 @@ func newTestServer(handler func(w http.ResponseWriter, r *http.Request)) (*httpt
}
func TestNewClientFromConfig(t *testing.T) {
f := func(h func(w http.ResponseWriter, r *http.Request), httpCfg *promauth.HTTPClientConfig, expectedMessage string) {
t.Helper()
s, err := newTestServer(h)
if err != nil {
t.Fatalf("cannot create test server: %s", err)
}
defer s.Close()
client, err := NewClient("http://0.0.0.0:1234", nil, &proxy.URL{}, nil, httpCfg)
if err != nil {
t.Fatalf("can't create a client from this config: %+v", httpCfg)
}
response, err := client.client.client.Get(s.URL)
if err != nil {
t.Fatalf("can't connect to the test server using this config: %+v: %v", httpCfg, err)
}
message, err := io.ReadAll(response.Body)
response.Body.Close()
if err != nil {
t.Fatalf("Can't read the server response body using this config: %+v", httpCfg)
}
trimMessage := strings.TrimSpace(string(message))
if expectedMessage != trimMessage {
t.Fatalf("The expected message (%s) differs from the obtained message (%s) using this config: %+v", expectedMessage, trimMessage, httpCfg)
}
}
// verify enabled redirects
allowed := true
notAllowed := false
newClientValidConfig := []struct {
httpCfg promauth.HTTPClientConfig
handler func(w http.ResponseWriter, r *http.Request)
expectedMessage string
}{
{
httpCfg: promauth.HTTPClientConfig{
FollowRedirects: &allowed,
},
handler: func(w http.ResponseWriter, r *http.Request) {
handlerRedirect := func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/redirected":
fmt.Fprint(w, "I'm here to serve you!!!")
@ -39,14 +61,14 @@ func TestNewClientFromConfig(t *testing.T) {
w.WriteHeader(http.StatusFound)
fmt.Fprint(w, "It should follow the redirect.")
}
},
expectedMessage: "I'm here to serve you!!!",
},
{
httpCfg: promauth.HTTPClientConfig{
FollowRedirects: &notAllowed,
},
handler: func(w http.ResponseWriter, r *http.Request) {
}
f(handlerRedirect, &promauth.HTTPClientConfig{
FollowRedirects: &allowed,
}, "I'm here to serve you!!!")
// Verify disabled redirects
notAllowed := false
handlerNoRedirect := func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/redirected":
fmt.Fprint(w, "The redirection was followed.")
@ -55,41 +77,8 @@ func TestNewClientFromConfig(t *testing.T) {
w.WriteHeader(http.StatusFound)
fmt.Fprint(w, "I'm before redirect")
}
},
expectedMessage: "I'm before redirect",
},
}
for _, validConfig := range newClientValidConfig {
testServer, err := newTestServer(validConfig.handler)
if err != nil {
t.Fatal(err.Error())
}
defer testServer.Close()
client, err := NewClient("http://0.0.0.0:1234", nil, &proxy.URL{}, nil, &validConfig.httpCfg)
if err != nil {
t.Errorf("Can't create a client from this config: %+v", validConfig.httpCfg)
continue
}
response, err := client.client.client.Get(testServer.URL)
if err != nil {
t.Errorf("Can't connect to the test server using this config: %+v: %v", validConfig.httpCfg, err)
continue
}
message, err := io.ReadAll(response.Body)
response.Body.Close()
if err != nil {
t.Errorf("Can't read the server response body using this config: %+v", validConfig.httpCfg)
continue
}
trimMessage := strings.TrimSpace(string(message))
if validConfig.expectedMessage != trimMessage {
t.Errorf("The expected message (%s) differs from the obtained message (%s) using this config: %+v",
validConfig.expectedMessage, trimMessage, validConfig.httpCfg)
}
}
f(handlerNoRedirect, &promauth.HTTPClientConfig{
FollowRedirects: &notAllowed,
}, "I'm before redirect")
}

View file

@ -9,7 +9,7 @@ import (
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/graphite"
)
func Test_streamContext_Read(t *testing.T) {
func TestStreamContextRead(t *testing.T) {
f := func(s string, rowsExpected *graphite.Rows) {
t.Helper()
ctx := getStreamContext(strings.NewReader(s))

View file

@ -4,53 +4,45 @@ import (
"testing"
)
func Test_Validate(t *testing.T) {
tests := []struct {
name string
snapshotName string
want bool
}{
{
name: "empty snapshot name",
snapshotName: "",
want: false,
},
{
name: "short snapshot name",
snapshotName: "",
want: false,
},
{
name: "short first part of the snapshot name",
snapshotName: "2022050312163-16EB56ADB4110CF2",
want: false,
},
{
name: "short second part of the snapshot name",
snapshotName: "20220503121638-16EB56ADB4110CF",
want: true,
},
{
name: "correct snapshot name",
snapshotName: "20220503121638-16EB56ADB4110CF2",
want: true,
},
{
name: "invalid time part snapshot name",
snapshotName: "00000000000000-16EB56ADB4110CF2",
want: false,
},
{
name: "not enough parts of the snapshot name",
snapshotName: "2022050312163816EB56ADB4110CF2",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := Validate(tt.snapshotName); (err == nil) != tt.want {
t.Errorf("checkSnapshotName() = %v, want %v", err, tt.want)
}
})
func TestValidate_Failure(t *testing.T) {
f := func(snapshotName string) {
t.Helper()
err := Validate(snapshotName)
if err == nil {
t.Fatalf("expecting non-nil error")
}
}
// empty snapshot name
f("")
// short snapshot name
f("foo")
// short first part of the snapshot name
f("2022050312163-16EB56ADB4110CF2")
// invalid time part snapshot name
f("00000000000000-16EB56ADB4110CF2")
// not enough parts of the snapshot name
f("2022050312163816EB56ADB4110CF2")
}
func TestValidate_Success(t *testing.T) {
f := func(snapshotName string) {
t.Helper()
err := Validate(snapshotName)
if err != nil {
t.Fatalf("checkSnapshotName() error: %s", err)
}
}
// short second part of the snapshot name - this is OK
f("20220503121638-16EB56ADB4110CF")
//correct snapshot name
f("20220503121638-16EB56ADB4110CF2")
}