node_exporter/collector/tcpstat_linux_test.go

164 lines
3.8 KiB
Go
Raw Normal View History

2015-09-26 08:36:40 -07:00
// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !notcpstat
// +build !notcpstat
2015-03-24 04:34:48 -07:00
package collector
import (
"bytes"
"encoding/binary"
"syscall"
2015-03-24 04:34:48 -07:00
"testing"
"github.com/josharian/native"
"github.com/mdlayher/netlink"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
2015-03-24 04:34:48 -07:00
)
func encodeDiagMsg(m InetDiagMsg) []byte {
var buf bytes.Buffer
if err := binary.Write(&buf, native.Endian, m); err != nil {
panic(err)
}
return buf.Bytes()
}
func Test_parseTCPStats(t *testing.T) {
msg := []netlink.Message{
{
Data: encodeDiagMsg(InetDiagMsg{
Family: syscall.AF_INET,
State: uint8(tcpEstablished),
Timer: 0,
Retrans: 0,
ID: InetDiagSockID{},
Expires: 0,
RQueue: 11,
WQueue: 21,
UID: 0,
Inode: 0,
}),
},
{
Data: encodeDiagMsg(InetDiagMsg{
Family: syscall.AF_INET,
State: uint8(tcpListen),
Timer: 0,
Retrans: 0,
ID: InetDiagSockID{},
Expires: 0,
RQueue: 11,
WQueue: 21,
UID: 0,
Inode: 0,
}),
},
}
stats, err := parseTCPStats(msg)
2015-03-24 04:34:48 -07:00
if err != nil {
t.Fatal(err)
}
assertStat(t, stats, tcpEstablished, 1)
assertStat(t, stats, tcpListen, 1)
assertStat(t, stats, tcpTxQueuedBytes, 42)
assertStat(t, stats, tcpRxQueuedBytes, 22)
}
func assertStat(t *testing.T, stats map[tcpConnectionState]float64, state tcpConnectionState, expected int) {
t.Helper()
if got := int(stats[state]); got != expected {
t.Errorf("expected %s = %d, got %d", state.String(), expected, got)
}
}
func Test_emitTCPStatsPerPort(t *testing.T) {
msg := []netlink.Message{
{
Data: encodeDiagMsg(InetDiagMsg{
State: uint8(tcpEstablished),
ID: InetDiagSockID{SourcePort: [2]byte{0, 80}},
}),
},
{
Data: encodeDiagMsg(InetDiagMsg{
State: uint8(tcpListen),
ID: InetDiagSockID{DestPort: [2]byte{0, 123}},
}),
},
{
Data: encodeDiagMsg(InetDiagMsg{
State: uint8(tcpTimeWait),
ID: InetDiagSockID{DestPort: [2]byte{0, 123}},
}),
},
}
var metrics []string
collector := &tcpStatCollector{
desc: typedDesc{
desc: prometheus.NewDesc("test_tcp_stat", "Test metric", []string{"state", "port", "direction"}, nil),
valueType: prometheus.GaugeValue,
},
2015-03-24 04:34:48 -07:00
}
ch := make(chan prometheus.Metric, 10)
emitTCPStatsPerPort(collector, ch, msg, []string{"80"}, "source", true)
emitTCPStatsPerPort(collector, ch, msg, []string{"123"}, "dest", false)
close(ch)
for m := range ch {
d := &dto.Metric{}
if err := m.Write(d); err != nil {
t.Fatalf("failed to write metric: %v", err)
}
var state, port, direction string
for _, label := range d.Label {
switch label.GetName() {
case "state":
state = label.GetValue()
case "port":
port = label.GetValue()
case "direction":
direction = label.GetValue()
}
}
metrics = append(metrics, state+"_"+port+"_"+direction)
2015-03-24 04:34:48 -07:00
}
expected := map[string]bool{
"established_80_source": true,
"listen_123_dest": true,
"time_wait_123_dest": true,
}
for _, metric := range metrics {
if !expected[metric] {
t.Errorf("unexpected metric emitted: %s", metric)
}
delete(expected, metric)
}
for k := range expected {
t.Errorf("expected metric missing: %s", k)
}
}