From b975419bc718200856a0384de35d2f8dec0f116e Mon Sep 17 00:00:00 2001 From: Cameron Sparr Date: Fri, 13 Nov 2015 12:51:37 -0700 Subject: [PATCH] Apache plugin unit tests and README --- plugins/apache/README.md | 45 +++++++++++ plugins/apache/apache.go | 2 +- plugins/apache/apache_test.go | 80 +++++++++++++++++++ .../kafka_consumer_integration_test.go | 2 +- plugins/kafka_consumer/kafka_consumer_test.go | 2 +- plugins/system/system_test.go | 2 +- testutil/accumulator.go | 66 ++++++++------- 7 files changed, 165 insertions(+), 34 deletions(-) create mode 100644 plugins/apache/README.md create mode 100644 plugins/apache/apache_test.go diff --git a/plugins/apache/README.md b/plugins/apache/README.md new file mode 100644 index 000000000..0f2f0deed --- /dev/null +++ b/plugins/apache/README.md @@ -0,0 +1,45 @@ +# Telegraf plugin: Apache + +#### Plugin arguments: +- **urls** []string: List of apache-status URLs to collect from. + +#### Description + +The Apache plugin collects from the /server-status?auto URL. See +[apache.org/server-status?auto](http://www.apache.org/server-status?auto) for an +example. And +[here](http://httpd.apache.org/docs/2.2/mod/mod_status.html) for the apache +mod_status documentation. + +# Measurements: + +Meta: +- tags: `port=`, `server=url` + +- apache_TotalAccesses +- apache_TotalkBytes +- apache_CPULoad +- apache_Uptime +- apache_ReqPerSec +- apache_BytesPerSec +- apache_BytesPerReq +- apache_BusyWorkers +- apache_IdleWorkers +- apache_ConnsTotal +- apache_ConnsAsyncWriting +- apache_ConnsAsyncKeepAlive +- apache_ConnsAsyncClosing + +### Scoreboard measurements + +- apache_scboard_waiting +- apache_scboard_starting +- apache_scboard_reading +- apache_scboard_sending +- apache_scboard_keepalive +- apache_scboard_dnslookup +- apache_scboard_closing +- apache_scboard_logging +- apache_scboard_finishing +- apache_scboard_idle_cleanup +- apache_scboard_open diff --git a/plugins/apache/apache.go b/plugins/apache/apache.go index 86f9cda2d..3cebecb22 100644 --- a/plugins/apache/apache.go +++ b/plugins/apache/apache.go @@ -84,7 +84,7 @@ func (n *Apache) gatherUrl(addr *url.URL, acc plugins.Accumulator) error { case "Scoreboard": n.gatherScores(part, acc, tags) default: - value, err := strconv.ParseFloat(part, 32) + value, err := strconv.ParseFloat(part, 64) if err != nil { continue } diff --git a/plugins/apache/apache_test.go b/plugins/apache/apache_test.go new file mode 100644 index 000000000..018542884 --- /dev/null +++ b/plugins/apache/apache_test.go @@ -0,0 +1,80 @@ +package apache + +import ( + "fmt" + "net/http" + "net/http/httptest" + "testing" + + "github.com/influxdb/telegraf/testutil" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var apacheStatus = ` +Total Accesses: 129811861 +Total kBytes: 5213701865 +CPULoad: 6.51929 +Uptime: 941553 +ReqPerSec: 137.87 +BytesPerSec: 5670240 +BytesPerReq: 41127.4 +BusyWorkers: 270 +IdleWorkers: 630 +ConnsTotal: 1451 +ConnsAsyncWriting: 32 +ConnsAsyncKeepAlive: 945 +ConnsAsyncClosing: 205 +Scoreboard: WW_____W_RW_R_W__RRR____WR_W___WW________W_WW_W_____R__R_WR__WRWR_RRRW___R_RWW__WWWRW__R_RW___RR_RW_R__W__WR_WWW______WWR__R___R_WR_W___RW______RR________________W______R__RR______W________________R____R__________________________RW_W____R_____W_R_________________R____RR__W___R_R____RW______R____W______W_W_R_R______R__R_R__________R____W_______WW____W____RR__W_____W_R_______W__________W___W____________W_______WRR_R_W____W_____R____W_WW_R____RRW__W............................................................................................................................................................................................................................................................................................................WRRWR____WR__RR_R___RWR_________W_R____RWRRR____R_R__RW_R___WWW_RW__WR_RRR____W___R____WW_R__R___RR_W_W_RRRRWR__RRWR__RRW_W_RRRW_R_RR_W__RR_RWRR_R__R___RR_RR______R__RR____R_____W_R_R_R__R__R__________W____WW_R___R_R___R_________RR__RR____RWWWW___W_R________R_R____R_W___W___R___W_WRRWW_______R__W_RW_______R________RR__R________W_______________________W_W______________RW_________WR__R___R__R_______________WR_R_________W___RW_____R____________W____...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... +` + +func TestHTTPInflux(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + fmt.Fprintln(w, apacheStatus) + })) + defer ts.Close() + + a := Apache{ + Urls: []string{ts.URL}, + } + + var acc testutil.Accumulator + err := a.Gather(&acc) + require.NoError(t, err) + + testInt := []struct { + measurement string + value float64 + }{ + {"TotalAccesses", 1.29811861e+08}, + {"TotalkBytes", 5.213701865e+09}, + {"CPULoad", 6.51929}, + {"Uptime", 941553}, + {"ReqPerSec", 137.87}, + {"BytesPerSec", 5.67024e+06}, + {"BytesPerReq", 41127.4}, + {"BusyWorkers", 270}, + {"IdleWorkers", 630}, + {"ConnsTotal", 1451}, + {"ConnsAsyncWriting", 32}, + {"ConnsAsyncKeepAlive", 945}, + {"ConnsAsyncClosing", 205}, + {"scboard_waiting", 630}, + {"scboard_starting", 0}, + {"scboard_reading", 157}, + {"scboard_sending", 113}, + {"scboard_keepalive", 0}, + {"scboard_dnslookup", 0}, + {"scboard_closing", 0}, + {"scboard_logging", 0}, + {"scboard_finishing", 0}, + {"scboard_idle_cleanup", 0}, + {"scboard_open", 2850}, + } + + for _, test := range testInt { + assert.True(t, acc.CheckValue(test.measurement, test.value)) + } +} diff --git a/plugins/kafka_consumer/kafka_consumer_integration_test.go b/plugins/kafka_consumer/kafka_consumer_integration_test.go index c94a2198d..6513a4600 100644 --- a/plugins/kafka_consumer/kafka_consumer_integration_test.go +++ b/plugins/kafka_consumer/kafka_consumer_integration_test.go @@ -47,7 +47,7 @@ func TestReadsMetricsFromKafka(t *testing.T) { point := acc.Points[0] assert.Equal(t, "cpu_load_short", point.Measurement) - assert.Equal(t, map[string]interface{}{"value": 23422.0}, point.Values) + assert.Equal(t, map[string]interface{}{"value": 23422.0}, point.Fields) assert.Equal(t, map[string]string{ "host": "server01", "direction": "in", diff --git a/plugins/kafka_consumer/kafka_consumer_test.go b/plugins/kafka_consumer/kafka_consumer_test.go index 0385f54be..6a97e3227 100644 --- a/plugins/kafka_consumer/kafka_consumer_test.go +++ b/plugins/kafka_consumer/kafka_consumer_test.go @@ -64,7 +64,7 @@ func TestEmitMetricsSendMetricsToAcc(t *testing.T) { point := acc.Points[0] assert.Equal(t, "cpu_load_short", point.Measurement) - assert.Equal(t, map[string]interface{}{"value": 23422.0}, point.Values) + assert.Equal(t, map[string]interface{}{"value": 23422.0}, point.Fields) assert.Equal(t, map[string]string{ "host": "server01", "direction": "in", diff --git a/plugins/system/system_test.go b/plugins/system/system_test.go index 389965e3b..094405136 100644 --- a/plugins/system/system_test.go +++ b/plugins/system/system_test.go @@ -393,7 +393,7 @@ func assertContainsTaggedFloat( for _, pt := range acc.Points { if pt.Measurement == measurement { if (tags == nil) || reflect.DeepEqual(pt.Tags, tags) { - if value, ok := pt.Values["value"].(float64); ok { + if value, ok := pt.Fields["value"].(float64); ok { actualValue = value if (value >= expectedValue-delta) && (value <= expectedValue+delta) { // Found the point, return without failing diff --git a/testutil/accumulator.go b/testutil/accumulator.go index d8f44ddf8..d31c71ef5 100644 --- a/testutil/accumulator.go +++ b/testutil/accumulator.go @@ -11,10 +11,14 @@ import ( type Point struct { Measurement string Tags map[string]string - Values map[string]interface{} + Fields map[string]interface{} Time time.Time } +func (p *Point) String() string { + return fmt.Sprintf("%s %v", p.Measurement, p.Fields) +} + // Accumulator defines a mocked out accumulator type Accumulator struct { sync.Mutex @@ -28,44 +32,40 @@ func (a *Accumulator) Add( tags map[string]string, t ...time.Time, ) { - a.Lock() - defer a.Unlock() - if tags == nil { - tags = map[string]string{} - } - a.Points = append( - a.Points, - &Point{ - Measurement: measurement, - Values: map[string]interface{}{"value": value}, - Tags: tags, - }, - ) + fields := map[string]interface{}{"value": value} + a.AddFields(measurement, fields, tags, t...) } // AddFields adds a measurement point with a specified timestamp. func (a *Accumulator) AddFields( measurement string, - values map[string]interface{}, + fields map[string]interface{}, tags map[string]string, timestamp ...time.Time, ) { a.Lock() defer a.Unlock() + if tags == nil { + tags = map[string]string{} + } + var t time.Time if len(timestamp) > 0 { t = timestamp[0] } else { t = time.Now() } + + p := &Point{ + Measurement: measurement, + Fields: fields, + Tags: tags, + Time: t, + } + a.Points = append( a.Points, - &Point{ - Measurement: measurement, - Values: values, - Tags: tags, - Time: t, - }, + p, ) } @@ -116,10 +116,16 @@ func (a *Accumulator) CheckValue(measurement string, val interface{}) bool { func (a *Accumulator) CheckFieldsValue(measurement string, fields map[string]interface{}) bool { for _, p := range a.Points { if p.Measurement == measurement { - return reflect.DeepEqual(fields, p.Values) + if reflect.DeepEqual(fields, p.Fields) { + return true + } else { + fmt.Printf("Measurement %s Failure, expected: %v, got %v\n", + measurement, fields, p.Fields) + return false + } } } - fmt.Printf("CheckFieldsValue failed, measurement %s, fields %s", measurement, fields) + fmt.Printf("Measurement %s, fields %s not found\n", measurement, fields) return false } @@ -171,8 +177,8 @@ func (a *Accumulator) ValidateTaggedFieldsValue( } if p.Measurement == measurement { - if !reflect.DeepEqual(fields, p.Values) { - return fmt.Errorf("%v != %v ", fields, p.Values) + if !reflect.DeepEqual(fields, p.Fields) { + return fmt.Errorf("%v != %v ", fields, p.Fields) } return nil } @@ -203,9 +209,9 @@ func (a *Accumulator) ValidateTaggedFields( } if p.Measurement == measurement { - if !reflect.DeepEqual(fields, p.Values) { + if !reflect.DeepEqual(fields, p.Fields) { return fmt.Errorf("%v (%T) != %v (%T)", - p.Values, p.Values, fields, fields) + p.Fields, p.Fields, fields, fields) } return nil } @@ -217,7 +223,7 @@ func (a *Accumulator) ValidateTaggedFields( func (a *Accumulator) HasIntValue(measurement string) bool { for _, p := range a.Points { if p.Measurement == measurement { - _, ok := p.Values["value"].(int64) + _, ok := p.Fields["value"].(int64) return ok } } @@ -229,7 +235,7 @@ func (a *Accumulator) HasIntValue(measurement string) bool { func (a *Accumulator) HasUIntValue(measurement string) bool { for _, p := range a.Points { if p.Measurement == measurement { - _, ok := p.Values["value"].(uint64) + _, ok := p.Fields["value"].(uint64) return ok } } @@ -241,7 +247,7 @@ func (a *Accumulator) HasUIntValue(measurement string) bool { func (a *Accumulator) HasFloatValue(measurement string) bool { for _, p := range a.Points { if p.Measurement == measurement { - _, ok := p.Values["value"].(float64) + _, ok := p.Fields["value"].(float64) return ok } }