package nginx_plus_api import ( "fmt" "net" "net/http" "net/http/httptest" "net/url" "testing" "github.com/influxdata/telegraf/testutil" "github.com/stretchr/testify/require" ) const processesPayload = ` { "respawned": 0 } ` const connectionsPayload = ` { "accepted": 1234567890000, "dropped": 2345678900000, "active": 345, "idle": 567 } ` const sslPayload = ` { "handshakes": 79572, "handshakes_failed": 21025, "session_reuses": 15762 } ` const resolverZonesPayload = ` { "resolver_zone1": { "requests": { "name": 25460, "srv": 130, "addr": 2580 }, "responses": { "noerror": 26499, "formerr": 0, "servfail": 3, "nxdomain": 0, "notimp": 0, "refused": 0, "timedout": 243, "unknown": 478 } }, "resolver_zone2": { "requests": { "name": 325460, "srv": 1130, "addr": 12580 }, "responses": { "noerror": 226499, "formerr": 0, "servfail": 283, "nxdomain": 0, "notimp": 0, "refused": 0, "timedout": 743, "unknown": 1478 } } } ` const httpRequestsPayload = ` { "total": 10624511, "current": 4 } ` const httpServerZonesPayload = ` { "site1": { "processing": 2, "requests": 736395, "responses": { "1xx": 0, "2xx": 727290, "3xx": 4614, "4xx": 934, "5xx": 1535, "total": 734373 }, "discarded": 2020, "received": 180157219, "sent": 20183175459 }, "site2": { "processing": 1, "requests": 185307, "responses": { "1xx": 0, "2xx": 112674, "3xx": 45383, "4xx": 2504, "5xx": 4419, "total": 164980 }, "discarded": 20326, "received": 51575327, "sent": 2983241510 } } ` const httpLocationZonesPayload = ` { "site1": { "requests": 736395, "responses": { "1xx": 0, "2xx": 727290, "3xx": 4614, "4xx": 934, "5xx": 1535, "total": 734373 }, "discarded": 2020, "received": 180157219, "sent": 20183175459 }, "site2": { "requests": 185307, "responses": { "1xx": 0, "2xx": 112674, "3xx": 45383, "4xx": 2504, "5xx": 4419, "total": 164980 }, "discarded": 20326, "received": 51575327, "sent": 2983241510 } } ` const httpUpstreamsPayload = ` { "trac-backend": { "peers": [ { "id": 0, "server": "10.0.0.1:8088", "name": "10.0.0.1:8088", "backup": false, "weight": 5, "state": "up", "active": 0, "requests": 667231, "header_time": 20, "response_time": 36, "responses": { "1xx": 0, "2xx": 666310, "3xx": 0, "4xx": 915, "5xx": 6, "total": 667231 }, "sent": 251946292, "received": 19222475454, "fails": 0, "unavail": 0, "health_checks": { "checks": 26214, "fails": 0, "unhealthy": 0, "last_passed": true }, "downtime": 0, "downstart": {}, "selected": {} }, { "id": 1, "server": "10.0.0.1:8089", "name": "10.0.0.1:8089", "backup": true, "weight": 1, "state": "unhealthy", "active": 0, "requests": 0, "responses": { "1xx": 0, "2xx": 0, "3xx": 0, "4xx": 0, "5xx": 0, "total": 0 }, "sent": 0, "received": 0, "fails": 0, "unavail": 0, "health_checks": { "checks": 26284, "fails": 26284, "unhealthy": 1, "last_passed": false }, "downtime": 262925617, "downstart": {}, "selected": {} } ], "keepalive": 0, "zombies": 0, "zone": "trac-backend" }, "hg-backend": { "peers": [ { "id": 0, "server": "10.0.0.1:8088", "name": "10.0.0.1:8088", "backup": false, "weight": 5, "state": "up", "active": 0, "requests": 667231, "header_time": 20, "response_time": 36, "responses": { "1xx": 0, "2xx": 666310, "3xx": 0, "4xx": 915, "5xx": 6, "total": 667231 }, "sent": 251946292, "received": 19222475454, "fails": 0, "unavail": 0, "health_checks": { "checks": 26214, "fails": 0, "unhealthy": 0, "last_passed": true }, "downtime": 0, "downstart": {}, "selected": {} }, { "id": 1, "server": "10.0.0.1:8089", "name": "10.0.0.1:8089", "backup": true, "weight": 1, "state": "unhealthy", "active": 0, "requests": 0, "responses": { "1xx": 0, "2xx": 0, "3xx": 0, "4xx": 0, "5xx": 0, "total": 0 }, "sent": 0, "received": 0, "fails": 0, "unavail": 0, "health_checks": { "checks": 26284, "fails": 26284, "unhealthy": 1, "last_passed": false }, "downtime": 262925617, "downstart": {}, "selected": {} } ], "keepalive": 0, "zombies": 0, "zone": "hg-backend" } } ` const httpCachesPayload = ` { "http-cache": { "size": 530915328, "max_size": 536870912, "cold": false, "hit": { "responses": 254032, "bytes": 6685627875 }, "stale": { "responses": 0, "bytes": 0 }, "updating": { "responses": 0, "bytes": 0 }, "revalidated": { "responses": 0, "bytes": 0 }, "miss": { "responses": 1619201, "bytes": 53841943822 }, "expired": { "responses": 45859, "bytes": 1656847080, "responses_written": 44992, "bytes_written": 1641825173 }, "bypass": { "responses": 200187, "bytes": 5510647548, "responses_written": 200173, "bytes_written": 44992 } }, "frontend-cache": { "size": 530915328, "max_size": 536870912, "cold": false, "hit": { "responses": 254032, "bytes": 6685627875 }, "stale": { "responses": 0, "bytes": 0 }, "updating": { "responses": 0, "bytes": 0 }, "revalidated": { "responses": 0, "bytes": 0 }, "miss": { "responses": 1619201, "bytes": 53841943822 }, "expired": { "responses": 45859, "bytes": 1656847080, "responses_written": 44992, "bytes_written": 1641825173 }, "bypass": { "responses": 200187, "bytes": 5510647548, "responses_written": 200173, "bytes_written": 44992 } } } ` const streamUpstreamsPayload = ` { "mysql_backends": { "peers": [ { "id": 0, "server": "10.0.0.1:12345", "name": "10.0.0.1:12345", "backup": false, "weight": 5, "state": "up", "active": 0, "max_conns": 30, "connecions": 1231, "sent": 251946292, "received": 19222475454, "fails": 0, "unavail": 0, "health_checks": { "checks": 26214, "fails": 0, "unhealthy": 0, "last_passed": true }, "downtime": 0, "downstart": {}, "selected": {} }, { "id": 1, "server": "10.0.0.1:12346", "name": "10.0.0.1:12346", "backup": true, "weight": 1, "state": "unhealthy", "active": 0, "max_conns": 30, "connections": 0, "sent": 0, "received": 0, "fails": 0, "unavail": 0, "health_checks": { "checks": 26284, "fails": 26284, "unhealthy": 1, "last_passed": false }, "downtime": 262925617, "downstart": {}, "selected": {} } ], "zombies": 0, "zone": "mysql_backends" }, "dns": { "peers": [ { "id": 0, "server": "10.0.0.1:12347", "name": "10.0.0.1:12347", "backup": false, "weight": 5, "state": "up", "active": 0, "max_conns": 30, "connections": 667231, "sent": 251946292, "received": 19222475454, "fails": 0, "unavail": 0, "health_checks": { "checks": 26214, "fails": 0, "unhealthy": 0, "last_passed": true }, "downtime": 0, "downstart": {}, "selected": {} }, { "id": 1, "server": "10.0.0.1:12348", "name": "10.0.0.1:12348", "backup": true, "weight": 1, "state": "unhealthy", "active": 0, "connections": 0, "max_conns": 30, "sent": 0, "received": 0, "fails": 0, "unavail": 0, "health_checks": { "checks": 26284, "fails": 26284, "unhealthy": 1, "last_passed": false }, "downtime": 262925617, "downstart": {}, "selected": {} } ], "zombies": 0, "zone": "dns" } } ` const streamServerZonesPayload = ` { "mysql-frontend": { "processing": 2, "connections": 270925, "sessions": { "2xx": 155564, "4xx": 0, "5xx": 0, "total": 270925 }, "discarded": 0, "received": 28988975, "sent": 3879346317 }, "dns": { "processing": 1, "connections": 155569, "sessions": { "2xx": 155564, "4xx": 0, "5xx": 0, "total": 155569 }, "discarded": 0, "received": 4200363, "sent": 20489184 } } ` func TestGatherProcessesMetrics(t *testing.T) { ts, n := prepareEndpoint(t, processesPath, defaultApiVersion, processesPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherProcessesMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_processes", map[string]interface{}{ "respawned": int(0), }, map[string]string{ "source": host, "port": port, }) } func TestGatherConnectionsMetrics(t *testing.T) { ts, n := prepareEndpoint(t, connectionsPath, defaultApiVersion, connectionsPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherConnectionsMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_connections", map[string]interface{}{ "accepted": int64(1234567890000), "dropped": int64(2345678900000), "active": int64(345), "idle": int64(567), }, map[string]string{ "source": host, "port": port, }) } func TestGatherSslMetrics(t *testing.T) { ts, n := prepareEndpoint(t, sslPath, defaultApiVersion, sslPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherSslMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_ssl", map[string]interface{}{ "handshakes": int64(79572), "handshakes_failed": int64(21025), "session_reuses": int64(15762), }, map[string]string{ "source": host, "port": port, }) } func TestGatherHttpRequestsMetrics(t *testing.T) { ts, n := prepareEndpoint(t, httpRequestsPath, defaultApiVersion, httpRequestsPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherHttpRequestsMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_requests", map[string]interface{}{ "total": int64(10624511), "current": int64(4), }, map[string]string{ "source": host, "port": port, }) } func TestGatherHttpServerZonesMetrics(t *testing.T) { ts, n := prepareEndpoint(t, httpServerZonesPath, defaultApiVersion, httpServerZonesPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherHttpServerZonesMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_server_zones", map[string]interface{}{ "discarded": int64(2020), "processing": int(2), "received": int64(180157219), "requests": int64(736395), "responses_1xx": int64(0), "responses_2xx": int64(727290), "responses_3xx": int64(4614), "responses_4xx": int64(934), "responses_5xx": int64(1535), "responses_total": int64(734373), "sent": int64(20183175459), }, map[string]string{ "source": host, "port": port, "zone": "site1", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_server_zones", map[string]interface{}{ "discarded": int64(20326), "processing": int(1), "received": int64(51575327), "requests": int64(185307), "responses_1xx": int64(0), "responses_2xx": int64(112674), "responses_3xx": int64(45383), "responses_4xx": int64(2504), "responses_5xx": int64(4419), "responses_total": int64(164980), "sent": int64(2983241510), }, map[string]string{ "source": host, "port": port, "zone": "site2", }) } func TestGatherHttpLocationZonesMetrics(t *testing.T) { ts, n := prepareEndpoint(t, httpLocationZonesPath, defaultApiVersion, httpLocationZonesPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherHttpLocationZonesMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_location_zones", map[string]interface{}{ "discarded": int64(2020), "received": int64(180157219), "requests": int64(736395), "responses_1xx": int64(0), "responses_2xx": int64(727290), "responses_3xx": int64(4614), "responses_4xx": int64(934), "responses_5xx": int64(1535), "responses_total": int64(734373), "sent": int64(20183175459), }, map[string]string{ "source": host, "port": port, "zone": "site1", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_location_zones", map[string]interface{}{ "discarded": int64(20326), "received": int64(51575327), "requests": int64(185307), "responses_1xx": int64(0), "responses_2xx": int64(112674), "responses_3xx": int64(45383), "responses_4xx": int64(2504), "responses_5xx": int64(4419), "responses_total": int64(164980), "sent": int64(2983241510), }, map[string]string{ "source": host, "port": port, "zone": "site2", }) } func TestGatherHttpUpstreamsMetrics(t *testing.T) { ts, n := prepareEndpoint(t, httpUpstreamsPath, defaultApiVersion, httpUpstreamsPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherHttpUpstreamsMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_upstreams", map[string]interface{}{ "keepalive": int(0), "zombies": int(0), }, map[string]string{ "source": host, "port": port, "upstream": "trac-backend", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_upstreams", map[string]interface{}{ "keepalive": int(0), "zombies": int(0), }, map[string]string{ "source": host, "port": port, "upstream": "hg-backend", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_upstream_peers", map[string]interface{}{ "active": int(0), "backup": false, "downtime": int64(0), "fails": int64(0), "header_time": int64(20), "healthchecks_checks": int64(26214), "healthchecks_fails": int64(0), "healthchecks_last_passed": true, "healthchecks_unhealthy": int64(0), "received": int64(19222475454), "requests": int64(667231), "response_time": int64(36), "responses_1xx": int64(0), "responses_2xx": int64(666310), "responses_3xx": int64(0), "responses_4xx": int64(915), "responses_5xx": int64(6), "responses_total": int64(667231), "sent": int64(251946292), "state": "up", "unavail": int64(0), "weight": int(5), }, map[string]string{ "source": host, "port": port, "upstream": "trac-backend", "upstream_address": "10.0.0.1:8088", "id": "0", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_upstream_peers", map[string]interface{}{ "active": int(0), "backup": true, "downtime": int64(262925617), "fails": int64(0), "healthchecks_checks": int64(26284), "healthchecks_fails": int64(26284), "healthchecks_last_passed": false, "healthchecks_unhealthy": int64(1), "received": int64(0), "requests": int64(0), "responses_1xx": int64(0), "responses_2xx": int64(0), "responses_3xx": int64(0), "responses_4xx": int64(0), "responses_5xx": int64(0), "responses_total": int64(0), "sent": int64(0), "state": "unhealthy", "unavail": int64(0), "weight": int(1), }, map[string]string{ "source": host, "port": port, "upstream": "trac-backend", "upstream_address": "10.0.0.1:8089", "id": "1", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_upstream_peers", map[string]interface{}{ "active": int(0), "backup": false, "downtime": int64(0), "fails": int64(0), "header_time": int64(20), "healthchecks_checks": int64(26214), "healthchecks_fails": int64(0), "healthchecks_last_passed": true, "healthchecks_unhealthy": int64(0), "received": int64(19222475454), "requests": int64(667231), "response_time": int64(36), "responses_1xx": int64(0), "responses_2xx": int64(666310), "responses_3xx": int64(0), "responses_4xx": int64(915), "responses_5xx": int64(6), "responses_total": int64(667231), "sent": int64(251946292), "state": "up", "unavail": int64(0), "weight": int(5), }, map[string]string{ "source": host, "port": port, "upstream": "hg-backend", "upstream_address": "10.0.0.1:8088", "id": "0", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_upstream_peers", map[string]interface{}{ "active": int(0), "backup": true, "downtime": int64(262925617), "fails": int64(0), "healthchecks_checks": int64(26284), "healthchecks_fails": int64(26284), "healthchecks_last_passed": false, "healthchecks_unhealthy": int64(1), "received": int64(0), "requests": int64(0), "responses_1xx": int64(0), "responses_2xx": int64(0), "responses_3xx": int64(0), "responses_4xx": int64(0), "responses_5xx": int64(0), "responses_total": int64(0), "sent": int64(0), "state": "unhealthy", "unavail": int64(0), "weight": int(1), }, map[string]string{ "source": host, "port": port, "upstream": "hg-backend", "upstream_address": "10.0.0.1:8089", "id": "1", }) } func TestGatherHttpCachesMetrics(t *testing.T) { ts, n := prepareEndpoint(t, httpCachesPath, defaultApiVersion, httpCachesPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherHttpCachesMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_caches", map[string]interface{}{ "bypass_bytes": int64(5510647548), "bypass_bytes_written": int64(44992), "bypass_responses": int64(200187), "bypass_responses_written": int64(200173), "cold": false, "expired_bytes": int64(1656847080), "expired_bytes_written": int64(1641825173), "expired_responses": int64(45859), "expired_responses_written": int64(44992), "hit_bytes": int64(6685627875), "hit_responses": int64(254032), "max_size": int64(536870912), "miss_bytes": int64(53841943822), "miss_bytes_written": int64(0), "miss_responses": int64(1619201), "miss_responses_written": int64(0), "revalidated_bytes": int64(0), "revalidated_responses": int64(0), "size": int64(530915328), "stale_bytes": int64(0), "stale_responses": int64(0), "updating_bytes": int64(0), "updating_responses": int64(0), }, map[string]string{ "source": host, "port": port, "cache": "http-cache", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_http_caches", map[string]interface{}{ "bypass_bytes": int64(5510647548), "bypass_bytes_written": int64(44992), "bypass_responses": int64(200187), "bypass_responses_written": int64(200173), "cold": false, "expired_bytes": int64(1656847080), "expired_bytes_written": int64(1641825173), "expired_responses": int64(45859), "expired_responses_written": int64(44992), "hit_bytes": int64(6685627875), "hit_responses": int64(254032), "max_size": int64(536870912), "miss_bytes": int64(53841943822), "miss_bytes_written": int64(0), "miss_responses": int64(1619201), "miss_responses_written": int64(0), "revalidated_bytes": int64(0), "revalidated_responses": int64(0), "size": int64(530915328), "stale_bytes": int64(0), "stale_responses": int64(0), "updating_bytes": int64(0), "updating_responses": int64(0), }, map[string]string{ "source": host, "port": port, "cache": "frontend-cache", }) } func TestGatherResolverZonesMetrics(t *testing.T) { ts, n := prepareEndpoint(t, resolverZonesPath, defaultApiVersion, resolverZonesPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherResolverZonesMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_resolver_zones", map[string]interface{}{ "name": int64(25460), "srv": int64(130), "addr": int64(2580), "noerror": int64(26499), "formerr": int64(0), "servfail": int64(3), "nxdomain": int64(0), "notimp": int64(0), "refused": int64(0), "timedout": int64(243), "unknown": int64(478), }, map[string]string{ "source": host, "port": port, "zone": "resolver_zone1", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_resolver_zones", map[string]interface{}{ "name": int64(325460), "srv": int64(1130), "addr": int64(12580), "noerror": int64(226499), "formerr": int64(0), "servfail": int64(283), "nxdomain": int64(0), "notimp": int64(0), "refused": int64(0), "timedout": int64(743), "unknown": int64(1478), }, map[string]string{ "source": host, "port": port, "zone": "resolver_zone2", }) } func TestGatherStreamUpstreams(t *testing.T) { ts, n := prepareEndpoint(t, streamUpstreamsPath, defaultApiVersion, streamUpstreamsPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherStreamUpstreamsMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_stream_upstreams", map[string]interface{}{ "zombies": int(0), }, map[string]string{ "source": host, "port": port, "upstream": "mysql_backends", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_stream_upstreams", map[string]interface{}{ "zombies": int(0), }, map[string]string{ "source": host, "port": port, "upstream": "dns", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_stream_upstream_peers", map[string]interface{}{ "active": int(0), "backup": false, "connections": int64(0), "downtime": int64(0), "fails": int64(0), "healthchecks_checks": int64(26214), "healthchecks_fails": int64(0), "healthchecks_last_passed": true, "healthchecks_unhealthy": int64(0), "received": int64(19222475454), "sent": int64(251946292), "state": "up", "unavail": int64(0), "weight": int(5), }, map[string]string{ "source": host, "port": port, "upstream": "mysql_backends", "upstream_address": "10.0.0.1:12345", "id": "0", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_stream_upstream_peers", map[string]interface{}{ "active": int(0), "backup": true, "connections": int64(0), "downtime": int64(262925617), "fails": int64(0), "healthchecks_checks": int64(26284), "healthchecks_fails": int64(26284), "healthchecks_last_passed": false, "healthchecks_unhealthy": int64(1), "received": int64(0), "sent": int64(0), "state": "unhealthy", "unavail": int64(0), "weight": int(1), }, map[string]string{ "source": host, "port": port, "upstream": "mysql_backends", "upstream_address": "10.0.0.1:12346", "id": "1", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_stream_upstream_peers", map[string]interface{}{ "active": int(0), "backup": false, "connections": int64(667231), "downtime": int64(0), "fails": int64(0), "healthchecks_checks": int64(26214), "healthchecks_fails": int64(0), "healthchecks_last_passed": true, "healthchecks_unhealthy": int64(0), "received": int64(19222475454), "sent": int64(251946292), "state": "up", "unavail": int64(0), "weight": int(5), }, map[string]string{ "source": host, "port": port, "upstream": "dns", "upstream_address": "10.0.0.1:12347", "id": "0", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_stream_upstream_peers", map[string]interface{}{ "active": int(0), "backup": true, "connections": int64(0), "downtime": int64(262925617), "fails": int64(0), "healthchecks_checks": int64(26284), "healthchecks_fails": int64(26284), "healthchecks_last_passed": false, "healthchecks_unhealthy": int64(1), "received": int64(0), "sent": int64(0), "state": "unhealthy", "unavail": int64(0), "weight": int(1), }, map[string]string{ "source": host, "port": port, "upstream": "dns", "upstream_address": "10.0.0.1:12348", "id": "1", }) } func TestGatherStreamServerZonesMetrics(t *testing.T) { ts, n := prepareEndpoint(t, streamServerZonesPath, defaultApiVersion, streamServerZonesPayload) defer ts.Close() var acc testutil.Accumulator addr, host, port := prepareAddr(t, ts) require.NoError(t, n.gatherStreamServerZonesMetrics(addr, &acc)) acc.AssertContainsTaggedFields( t, "nginx_plus_api_stream_server_zones", map[string]interface{}{ "connections": int(270925), "processing": int(2), "received": int64(28988975), "sent": int64(3879346317), }, map[string]string{ "source": host, "port": port, "zone": "mysql-frontend", }) acc.AssertContainsTaggedFields( t, "nginx_plus_api_stream_server_zones", map[string]interface{}{ "connections": int(155569), "processing": int(1), "received": int64(4200363), "sent": int64(20489184), }, map[string]string{ "source": host, "port": port, "zone": "dns", }) } func TestUnavailableEndpoints(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) })) defer ts.Close() n := &NginxPlusApi{ client: ts.Client(), } addr, err := url.Parse(ts.URL) if err != nil { t.Fatal(err) } var acc testutil.Accumulator n.gatherMetrics(addr, &acc) require.NoError(t, acc.FirstError()) } func TestServerError(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) })) defer ts.Close() n := &NginxPlusApi{ client: ts.Client(), } addr, err := url.Parse(ts.URL) if err != nil { t.Fatal(err) } var acc testutil.Accumulator n.gatherMetrics(addr, &acc) require.Error(t, acc.FirstError()) } func TestMalformedJSON(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") fmt.Fprintln(w, "this is not JSON") })) defer ts.Close() n := &NginxPlusApi{ client: ts.Client(), } addr, err := url.Parse(ts.URL) if err != nil { t.Fatal(err) } var acc testutil.Accumulator n.gatherMetrics(addr, &acc) require.Error(t, acc.FirstError()) } func TestUnknownContentType(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") })) defer ts.Close() n := &NginxPlusApi{ client: ts.Client(), } addr, err := url.Parse(ts.URL) if err != nil { t.Fatal(err) } var acc testutil.Accumulator n.gatherMetrics(addr, &acc) require.Error(t, acc.FirstError()) } func prepareAddr(t *testing.T, ts *httptest.Server) (*url.URL, string, string) { t.Helper() addr, err := url.Parse(fmt.Sprintf("%s/api", ts.URL)) if err != nil { t.Fatal(err) } host, port, err := net.SplitHostPort(addr.Host) if err != nil { host = addr.Host if addr.Scheme == "http" { port = "80" } else if addr.Scheme == "https" { port = "443" } else { port = "" } } return addr, host, port } func prepareEndpoint(t *testing.T, path string, apiVersion int64, payload string) (*httptest.Server, *NginxPlusApi) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var rsp string if r.URL.Path == fmt.Sprintf("/api/%d/%s", apiVersion, path) { rsp = payload w.Header()["Content-Type"] = []string{"application/json"} } else { t.Errorf("unknown request path") } fmt.Fprintln(w, rsp) })) n := &NginxPlusApi{ Urls: []string{fmt.Sprintf("%s/api", ts.URL)}, ApiVersion: apiVersion, } client, err := n.createHttpClient() if err != nil { t.Fatal(err) } n.client = client return ts, n }