442 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			442 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
| package dcos
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/influxdata/telegraf/testutil"
 | |
| 	"github.com/stretchr/testify/require"
 | |
| )
 | |
| 
 | |
| type mockClient struct {
 | |
| 	SetTokenF            func(token string)
 | |
| 	LoginF               func(ctx context.Context, sa *ServiceAccount) (*AuthToken, error)
 | |
| 	GetSummaryF          func(ctx context.Context) (*Summary, error)
 | |
| 	GetContainersF       func(ctx context.Context, node string) ([]Container, error)
 | |
| 	GetNodeMetricsF      func(ctx context.Context, node string) (*Metrics, error)
 | |
| 	GetContainerMetricsF func(ctx context.Context, node, container string) (*Metrics, error)
 | |
| 	GetAppMetricsF       func(ctx context.Context, node, container string) (*Metrics, error)
 | |
| }
 | |
| 
 | |
| func (c *mockClient) SetToken(token string) {
 | |
| 	c.SetTokenF(token)
 | |
| }
 | |
| 
 | |
| func (c *mockClient) Login(ctx context.Context, sa *ServiceAccount) (*AuthToken, error) {
 | |
| 	return c.LoginF(ctx, sa)
 | |
| }
 | |
| 
 | |
| func (c *mockClient) GetSummary(ctx context.Context) (*Summary, error) {
 | |
| 	return c.GetSummaryF(ctx)
 | |
| }
 | |
| 
 | |
| func (c *mockClient) GetContainers(ctx context.Context, node string) ([]Container, error) {
 | |
| 	return c.GetContainersF(ctx, node)
 | |
| }
 | |
| 
 | |
| func (c *mockClient) GetNodeMetrics(ctx context.Context, node string) (*Metrics, error) {
 | |
| 	return c.GetNodeMetricsF(ctx, node)
 | |
| }
 | |
| 
 | |
| func (c *mockClient) GetContainerMetrics(ctx context.Context, node, container string) (*Metrics, error) {
 | |
| 	return c.GetContainerMetricsF(ctx, node, container)
 | |
| }
 | |
| 
 | |
| func (c *mockClient) GetAppMetrics(ctx context.Context, node, container string) (*Metrics, error) {
 | |
| 	return c.GetAppMetricsF(ctx, node, container)
 | |
| }
 | |
| 
 | |
| func TestAddNodeMetrics(t *testing.T) {
 | |
| 	var tests = []struct {
 | |
| 		name    string
 | |
| 		metrics *Metrics
 | |
| 		check   func(*testutil.Accumulator) []bool
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "basic datapoint conversion",
 | |
| 			metrics: &Metrics{
 | |
| 				Datapoints: []DataPoint{
 | |
| 					{
 | |
| 						Name:  "process.count",
 | |
| 						Unit:  "count",
 | |
| 						Value: 42.0,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			check: func(acc *testutil.Accumulator) []bool {
 | |
| 				return []bool{acc.HasPoint(
 | |
| 					"dcos_node",
 | |
| 					map[string]string{
 | |
| 						"cluster": "a",
 | |
| 					},
 | |
| 					"process_count", 42.0,
 | |
| 				)}
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "path added as tag",
 | |
| 			metrics: &Metrics{
 | |
| 				Datapoints: []DataPoint{
 | |
| 					{
 | |
| 						Name: "filesystem.inode.free",
 | |
| 						Tags: map[string]string{
 | |
| 							"path": "/var/lib",
 | |
| 						},
 | |
| 						Unit:  "count",
 | |
| 						Value: 42.0,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			check: func(acc *testutil.Accumulator) []bool {
 | |
| 				return []bool{acc.HasPoint(
 | |
| 					"dcos_node",
 | |
| 					map[string]string{
 | |
| 						"cluster": "a",
 | |
| 						"path":    "/var/lib",
 | |
| 					},
 | |
| 					"filesystem_inode_free", 42.0,
 | |
| 				)}
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "interface added as tag",
 | |
| 			metrics: &Metrics{
 | |
| 				Datapoints: []DataPoint{
 | |
| 					{
 | |
| 						Name: "network.out.dropped",
 | |
| 						Tags: map[string]string{
 | |
| 							"interface": "eth0",
 | |
| 						},
 | |
| 						Unit:  "count",
 | |
| 						Value: 42.0,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			check: func(acc *testutil.Accumulator) []bool {
 | |
| 				return []bool{acc.HasPoint(
 | |
| 					"dcos_node",
 | |
| 					map[string]string{
 | |
| 						"cluster":   "a",
 | |
| 						"interface": "eth0",
 | |
| 					},
 | |
| 					"network_out_dropped", 42.0,
 | |
| 				)}
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "bytes unit appended to fieldkey",
 | |
| 			metrics: &Metrics{
 | |
| 				Datapoints: []DataPoint{
 | |
| 					{
 | |
| 						Name: "network.in",
 | |
| 						Tags: map[string]string{
 | |
| 							"interface": "eth0",
 | |
| 						},
 | |
| 						Unit:  "bytes",
 | |
| 						Value: 42.0,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			check: func(acc *testutil.Accumulator) []bool {
 | |
| 				return []bool{acc.HasPoint(
 | |
| 					"dcos_node",
 | |
| 					map[string]string{
 | |
| 						"cluster":   "a",
 | |
| 						"interface": "eth0",
 | |
| 					},
 | |
| 					"network_in_bytes", int64(42),
 | |
| 				)}
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "dimensions added as tags",
 | |
| 			metrics: &Metrics{
 | |
| 				Datapoints: []DataPoint{
 | |
| 					{
 | |
| 						Name:  "process.count",
 | |
| 						Tags:  map[string]string{},
 | |
| 						Unit:  "count",
 | |
| 						Value: 42.0,
 | |
| 					},
 | |
| 					{
 | |
| 						Name:  "memory.total",
 | |
| 						Tags:  map[string]string{},
 | |
| 						Unit:  "bytes",
 | |
| 						Value: 42,
 | |
| 					},
 | |
| 				},
 | |
| 				Dimensions: map[string]interface{}{
 | |
| 					"cluster_id": "c0760bbd-9e9d-434b-bd4a-39c7cdef8a63",
 | |
| 					"hostname":   "192.168.122.18",
 | |
| 					"mesos_id":   "2dfbbd28-29d2-411d-92c4-e2f84c38688e-S1",
 | |
| 				},
 | |
| 			},
 | |
| 			check: func(acc *testutil.Accumulator) []bool {
 | |
| 				return []bool{
 | |
| 					acc.HasPoint(
 | |
| 						"dcos_node",
 | |
| 						map[string]string{
 | |
| 							"cluster":  "a",
 | |
| 							"hostname": "192.168.122.18",
 | |
| 						},
 | |
| 						"process_count", 42.0),
 | |
| 					acc.HasPoint(
 | |
| 						"dcos_node",
 | |
| 						map[string]string{
 | |
| 							"cluster":  "a",
 | |
| 							"hostname": "192.168.122.18",
 | |
| 						},
 | |
| 						"memory_total_bytes", int64(42)),
 | |
| 				}
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			var acc testutil.Accumulator
 | |
| 			dcos := &DCOS{}
 | |
| 			dcos.addNodeMetrics(&acc, "a", tt.metrics)
 | |
| 			for i, ok := range tt.check(&acc) {
 | |
| 				require.True(t, ok, fmt.Sprintf("Index was not true: %d", i))
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| func TestAddContainerMetrics(t *testing.T) {
 | |
| 	var tests = []struct {
 | |
| 		name    string
 | |
| 		metrics *Metrics
 | |
| 		check   func(*testutil.Accumulator) []bool
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "container",
 | |
| 			metrics: &Metrics{
 | |
| 				Datapoints: []DataPoint{
 | |
| 					{
 | |
| 						Name: "net.rx.errors",
 | |
| 						Tags: map[string]string{
 | |
| 							"container_id":  "f25c457b-fceb-44f0-8f5b-38be34cbb6fb",
 | |
| 							"executor_id":   "telegraf.192fb45f-cc0c-11e7-af48-ea183c0b541a",
 | |
| 							"executor_name": "Command Executor (Task: telegraf.192fb45f-cc0c-11e7-af48-ea183c0b541a) (Command: NO EXECUTABLE)",
 | |
| 							"framework_id":  "ab2f3a8b-06db-4e8c-95b6-fb1940874a30-0001",
 | |
| 							"source":        "telegraf.192fb45f-cc0c-11e7-af48-ea183c0b541a",
 | |
| 						},
 | |
| 						Unit:  "count",
 | |
| 						Value: 42.0,
 | |
| 					},
 | |
| 				},
 | |
| 				Dimensions: map[string]interface{}{
 | |
| 					"cluster_id":          "c0760bbd-9e9d-434b-bd4a-39c7cdef8a63",
 | |
| 					"container_id":        "f25c457b-fceb-44f0-8f5b-38be34cbb6fb",
 | |
| 					"executor_id":         "telegraf.192fb45f-cc0c-11e7-af48-ea183c0b541a",
 | |
| 					"framework_id":        "ab2f3a8b-06db-4e8c-95b6-fb1940874a30-0001",
 | |
| 					"framework_name":      "marathon",
 | |
| 					"framework_principal": "dcos_marathon",
 | |
| 					"framework_role":      "slave_public",
 | |
| 					"hostname":            "192.168.122.18",
 | |
| 					"labels": map[string]string{
 | |
| 						"DCOS_SPACE": "/telegraf",
 | |
| 					},
 | |
| 					"mesos_id":  "2dfbbd28-29d2-411d-92c4-e2f84c38688e-S1",
 | |
| 					"task_id":   "telegraf.192fb45f-cc0c-11e7-af48-ea183c0b541a",
 | |
| 					"task_name": "telegraf",
 | |
| 				},
 | |
| 			},
 | |
| 			check: func(acc *testutil.Accumulator) []bool {
 | |
| 				return []bool{
 | |
| 					acc.HasPoint(
 | |
| 						"dcos_container",
 | |
| 						map[string]string{
 | |
| 							"cluster":      "a",
 | |
| 							"container_id": "f25c457b-fceb-44f0-8f5b-38be34cbb6fb",
 | |
| 							"hostname":     "192.168.122.18",
 | |
| 							"task_name":    "telegraf",
 | |
| 							"DCOS_SPACE":   "/telegraf",
 | |
| 						},
 | |
| 						"net_rx_errors",
 | |
| 						42.0,
 | |
| 					),
 | |
| 				}
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			var acc testutil.Accumulator
 | |
| 			dcos := &DCOS{}
 | |
| 			dcos.addContainerMetrics(&acc, "a", tt.metrics)
 | |
| 			for i, ok := range tt.check(&acc) {
 | |
| 				require.True(t, ok, fmt.Sprintf("Index was not true: %d", i))
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestAddAppMetrics(t *testing.T) {
 | |
| 	var tests = []struct {
 | |
| 		name    string
 | |
| 		metrics *Metrics
 | |
| 		check   func(*testutil.Accumulator) []bool
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "tags are optional",
 | |
| 			metrics: &Metrics{
 | |
| 				Datapoints: []DataPoint{
 | |
| 					{
 | |
| 						Name:  "dcos.metrics.module.container_throttled_bytes_per_sec",
 | |
| 						Unit:  "",
 | |
| 						Value: 42.0,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			check: func(acc *testutil.Accumulator) []bool {
 | |
| 				return []bool{
 | |
| 					acc.HasPoint(
 | |
| 						"dcos_app",
 | |
| 						map[string]string{
 | |
| 							"cluster": "a",
 | |
| 						},
 | |
| 						"container_throttled_bytes_per_sec", 42.0,
 | |
| 					),
 | |
| 				}
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name: "dimensions are tagged",
 | |
| 			metrics: &Metrics{
 | |
| 				Datapoints: []DataPoint{
 | |
| 					{
 | |
| 						Name:  "dcos.metrics.module.container_throttled_bytes_per_sec",
 | |
| 						Unit:  "",
 | |
| 						Value: 42.0,
 | |
| 					},
 | |
| 				},
 | |
| 				Dimensions: map[string]interface{}{
 | |
| 					"cluster_id":   "c0760bbd-9e9d-434b-bd4a-39c7cdef8a63",
 | |
| 					"container_id": "02d31175-1c01-4459-8520-ef8b1339bc52",
 | |
| 					"hostname":     "192.168.122.18",
 | |
| 					"mesos_id":     "2dfbbd28-29d2-411d-92c4-e2f84c38688e-S1",
 | |
| 				},
 | |
| 			},
 | |
| 			check: func(acc *testutil.Accumulator) []bool {
 | |
| 				return []bool{
 | |
| 					acc.HasPoint(
 | |
| 						"dcos_app",
 | |
| 						map[string]string{
 | |
| 							"cluster":      "a",
 | |
| 							"container_id": "02d31175-1c01-4459-8520-ef8b1339bc52",
 | |
| 							"hostname":     "192.168.122.18",
 | |
| 						},
 | |
| 						"container_throttled_bytes_per_sec", 42.0,
 | |
| 					),
 | |
| 				}
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			var acc testutil.Accumulator
 | |
| 			dcos := &DCOS{}
 | |
| 			dcos.addAppMetrics(&acc, "a", tt.metrics)
 | |
| 			for i, ok := range tt.check(&acc) {
 | |
| 				require.True(t, ok, fmt.Sprintf("Index was not true: %d", i))
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestGatherFilterNode(t *testing.T) {
 | |
| 	var tests = []struct {
 | |
| 		name        string
 | |
| 		nodeInclude []string
 | |
| 		nodeExclude []string
 | |
| 		client      Client
 | |
| 		check       func(*testutil.Accumulator) []bool
 | |
| 	}{
 | |
| 		{
 | |
| 			name: "cluster without nodes has no metrics",
 | |
| 			client: &mockClient{
 | |
| 				SetTokenF: func(token string) {},
 | |
| 				GetSummaryF: func(ctx context.Context) (*Summary, error) {
 | |
| 					return &Summary{
 | |
| 						Cluster: "a",
 | |
| 						Slaves:  []Slave{},
 | |
| 					}, nil
 | |
| 				},
 | |
| 			},
 | |
| 			check: func(acc *testutil.Accumulator) []bool {
 | |
| 				return []bool{
 | |
| 					acc.NMetrics() == 0,
 | |
| 				}
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			name:        "node include",
 | |
| 			nodeInclude: []string{"x"},
 | |
| 			client: &mockClient{
 | |
| 				SetTokenF: func(token string) {},
 | |
| 				GetSummaryF: func(ctx context.Context) (*Summary, error) {
 | |
| 					return &Summary{
 | |
| 						Cluster: "a",
 | |
| 						Slaves: []Slave{
 | |
| 							{ID: "x"},
 | |
| 							{ID: "y"},
 | |
| 						},
 | |
| 					}, nil
 | |
| 				},
 | |
| 				GetContainersF: func(ctx context.Context, node string) ([]Container, error) {
 | |
| 					return []Container{}, nil
 | |
| 				},
 | |
| 				GetNodeMetricsF: func(ctx context.Context, node string) (*Metrics, error) {
 | |
| 					return &Metrics{
 | |
| 						Datapoints: []DataPoint{
 | |
| 							{
 | |
| 								Name:  "value",
 | |
| 								Value: 42.0,
 | |
| 							},
 | |
| 						},
 | |
| 						Dimensions: map[string]interface{}{
 | |
| 							"hostname": "x",
 | |
| 						},
 | |
| 					}, nil
 | |
| 				},
 | |
| 			},
 | |
| 			check: func(acc *testutil.Accumulator) []bool {
 | |
| 				return []bool{
 | |
| 					acc.HasPoint(
 | |
| 						"dcos_node",
 | |
| 						map[string]string{
 | |
| 							"cluster":  "a",
 | |
| 							"hostname": "x",
 | |
| 						},
 | |
| 						"value", 42.0,
 | |
| 					),
 | |
| 					acc.NMetrics() == 1,
 | |
| 				}
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	for _, tt := range tests {
 | |
| 		t.Run(tt.name, func(t *testing.T) {
 | |
| 			var acc testutil.Accumulator
 | |
| 			dcos := &DCOS{
 | |
| 				NodeInclude: tt.nodeInclude,
 | |
| 				NodeExclude: tt.nodeExclude,
 | |
| 				client:      tt.client,
 | |
| 			}
 | |
| 			err := dcos.Gather(&acc)
 | |
| 			require.NoError(t, err)
 | |
| 			for i, ok := range tt.check(&acc) {
 | |
| 				require.True(t, ok, fmt.Sprintf("Index was not true: %d", i))
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 |