2014-12-31 21:37:58 +00:00
package graphite_test
2014-12-30 22:46:33 +00:00
import (
"bufio"
"bytes"
"fmt"
"net"
"strconv"
"testing"
"time"
2014-12-31 21:37:58 +00:00
"github.com/influxdb/influxdb"
"github.com/influxdb/influxdb/graphite"
2014-12-30 22:46:33 +00:00
)
2014-12-31 21:37:58 +00:00
func Test_DecodeNameAndTags ( t * testing . T ) {
2014-12-30 22:46:33 +00:00
var tests = [ ] struct {
2015-01-06 03:14:43 +00:00
test string
str string
name string
tags map [ string ] string
position string
2015-01-06 16:57:44 +00:00
separator string
2015-01-06 03:14:43 +00:00
err string
2014-12-30 22:46:33 +00:00
} {
{ test : "metric only" , str : "cpu" , name : "cpu" } ,
2015-01-06 03:14:43 +00:00
{ test : "metric with single series" , str : "cpu.hostname.server01" , name : "cpu" , tags : map [ string ] string { "hostname" : "server01" } } ,
{ test : "metric with multiple series" , str : "cpu.region.us-west.hostname.server01" , name : "cpu" , tags : map [ string ] string { "hostname" : "server01" , "region" : "us-west" } } ,
2014-12-30 22:46:33 +00:00
{ test : "no metric" , tags : make ( map [ string ] string ) , err : ` no name specified for metric. "" ` } ,
{ test : "wrong metric format" , str : "foo.cpu" , tags : make ( map [ string ] string ) , err : ` received "foo.cpu" which doesn't conform to format of key.value.key.value.metric or metric ` } ,
}
for _ , test := range tests {
t . Logf ( "testing %q..." , test . test )
2015-01-06 16:57:44 +00:00
name , tags , err := graphite . DecodeNameAndTags ( test . str , test . position , test . separator )
2014-12-31 21:37:58 +00:00
if errstr ( err ) != test . err {
t . Fatalf ( "err does not match. expected %v, got %v" , test . err , err )
2014-12-30 22:46:33 +00:00
}
if name != test . name {
t . Fatalf ( "name parse failer. expected %v, got %v" , test . name , name )
}
if len ( tags ) != len ( test . tags ) {
t . Fatalf ( "unexpected number of tags. expected %d, got %d" , len ( test . tags ) , len ( tags ) )
}
for k , v := range test . tags {
if tags [ k ] != v {
t . Fatalf ( "unexpected tag value for tags[%s]. expected %q, got %q" , k , v , tags [ k ] )
}
}
}
}
2014-12-31 21:37:58 +00:00
func Test_DecodeMetric ( t * testing . T ) {
2014-12-30 22:46:33 +00:00
testTime := time . Now ( )
epochTime := testTime . UnixNano ( ) / 1000000 // nanos to milliseconds
strTime := strconv . FormatInt ( epochTime , 10 )
var tests = [ ] struct {
2015-01-06 03:14:43 +00:00
test string
reader * bufio . Reader
name string
tags map [ string ] string
isInt bool
iv int64
fv float64
timestamp time . Time
2015-01-06 16:57:44 +00:00
position , separator string
2015-01-06 03:14:43 +00:00
err string
2014-12-30 22:46:33 +00:00
} {
{
2015-01-06 03:14:43 +00:00
test : "position first by default" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu.foo.bar 50 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
tags : map [ string ] string { "foo" : "bar" } ,
isInt : true ,
iv : 50 ,
timestamp : testTime ,
} ,
{
test : "position first if unable to determine" ,
position : "foo" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu.foo.bar 50 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
tags : map [ string ] string { "foo" : "bar" } ,
isInt : true ,
iv : 50 ,
timestamp : testTime ,
} ,
{
test : "position last if specified" ,
position : "last" ,
2014-12-30 22:46:33 +00:00
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` foo.bar.cpu 50 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
tags : map [ string ] string { "foo" : "bar" } ,
isInt : true ,
iv : 50 ,
timestamp : testTime ,
} ,
2015-01-06 03:14:43 +00:00
{
test : "position first if specified with no series" ,
position : "first" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu 50 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
tags : map [ string ] string { } ,
isInt : true ,
iv : 50 ,
timestamp : testTime ,
} ,
{
test : "position last if specified with no series" ,
position : "last" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu 50 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
tags : map [ string ] string { } ,
isInt : true ,
iv : 50 ,
timestamp : testTime ,
} ,
{
test : "sepeartor is . by default" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu.foo.bar 50 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
tags : map [ string ] string { "foo" : "bar" } ,
isInt : true ,
iv : 50 ,
timestamp : testTime ,
} ,
{
test : "sepeartor is . if specified" ,
2015-01-06 16:57:44 +00:00
separator : "." ,
2015-01-06 03:14:43 +00:00
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu.foo.bar 50 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
tags : map [ string ] string { "foo" : "bar" } ,
isInt : true ,
iv : 50 ,
timestamp : testTime ,
} ,
{
test : "sepeartor is - if specified" ,
2015-01-06 16:57:44 +00:00
separator : "-" ,
2015-01-06 03:14:43 +00:00
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu-foo-bar 50 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
tags : map [ string ] string { "foo" : "bar" } ,
isInt : true ,
iv : 50 ,
timestamp : testTime ,
} ,
{
test : "sepeartor is boo if specified" ,
2015-01-06 16:57:44 +00:00
separator : "boo" ,
2015-01-06 03:14:43 +00:00
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpuboofooboobar 50 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
tags : map [ string ] string { "foo" : "bar" } ,
isInt : true ,
iv : 50 ,
timestamp : testTime ,
} ,
{
test : "series + metric + integer value" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu.foo.bar 50 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
tags : map [ string ] string { "foo" : "bar" } ,
isInt : true ,
iv : 50 ,
timestamp : testTime ,
} ,
2014-12-30 22:46:33 +00:00
{
test : "metric only with float value" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu 50.554 ` + strTime + ` \n ` ) ) ) ,
name : "cpu" ,
isInt : false ,
fv : 50.554 ,
timestamp : testTime ,
} ,
{
test : "missing metric" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` 50.554 1419972457825\n ` ) ) ) ,
err : ` received "50.554 1419972457825" which doesn't have three fields ` ,
} ,
{
test : "should fail on eof" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` ` ) ) ) ,
err : ` EOF ` ,
} ,
{
test : "should fail on invalid key" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` foo.cpu 50.554 1419972457825\n ` ) ) ) ,
err : ` received "foo.cpu" which doesn't conform to format of key.value.key.value.metric or metric ` ,
} ,
{
test : "should fail parsing invalid float" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu 50.554z 1419972457825\n ` ) ) ) ,
err : ` strconv.ParseFloat: parsing "50.554z": invalid syntax ` ,
} ,
{
test : "should fail parsing invalid int" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu 50z 1419972457825\n ` ) ) ) ,
err : ` strconv.ParseFloat: parsing "50z": invalid syntax ` ,
} ,
{
test : "should fail parsing invalid time" ,
reader : bufio . NewReader ( bytes . NewBuffer ( [ ] byte ( ` cpu 50.554 14199724z57825\n ` ) ) ) ,
err : ` strconv.ParseInt: parsing "14199724z57825": invalid syntax ` ,
} ,
}
for _ , test := range tests {
t . Logf ( "testing %q..." , test . test )
2015-01-06 16:57:44 +00:00
g , err := graphite . DecodeMetric ( test . reader , test . position , test . separator )
2014-12-31 21:37:58 +00:00
if errstr ( err ) != test . err {
t . Fatalf ( "err does not match. expected %v, got %v" , test . err , err )
2014-12-30 22:46:33 +00:00
}
if err != nil {
// If we erred out,it was intended and the following tests won't work
continue
}
2014-12-31 21:37:58 +00:00
if g . Name != test . name {
t . Fatalf ( "name parse failer. expected %v, got %v" , test . name , g . Name )
2014-12-30 22:46:33 +00:00
}
2014-12-31 21:37:58 +00:00
if len ( g . Tags ) != len ( test . tags ) {
t . Fatalf ( "tags len mismatch. expected %d, got %d" , len ( test . tags ) , len ( g . Tags ) )
2014-12-30 22:46:33 +00:00
}
2015-01-06 03:14:43 +00:00
if test . isInt {
i := g . Value . ( int64 )
if i != test . iv {
t . Fatalf ( "integerValue value mismatch. expected %v, got %v" , test . iv , g . Value )
}
} else {
f := g . Value . ( float64 )
if g . Value != f {
t . Fatalf ( "floatValue value mismatch. expected %v, got %v" , test . fv , f )
}
2014-12-30 22:46:33 +00:00
}
2014-12-31 21:37:58 +00:00
if g . Timestamp . UnixNano ( ) / 1000000 != test . timestamp . UnixNano ( ) / 1000000 {
t . Fatalf ( "timestamp value mismatch. expected %v, got %v" , test . timestamp . UnixNano ( ) , g . Timestamp . UnixNano ( ) )
2014-12-30 22:46:33 +00:00
}
}
}
type testServer string
2014-12-31 21:37:58 +00:00
func ( testServer ) DefaultRetentionPolicy ( database string ) ( * influxdb . RetentionPolicy , error ) {
return & influxdb . RetentionPolicy { } , nil
2014-12-30 22:46:33 +00:00
}
func ( testServer ) WriteSeries ( database , retentionPolicy , name string , tags map [ string ] string , timestamp time . Time , values map [ string ] interface { } ) error {
return nil
}
2014-12-31 21:37:58 +00:00
type testServerFailedRetention string
func ( testServerFailedRetention ) DefaultRetentionPolicy ( database string ) ( * influxdb . RetentionPolicy , error ) {
return & influxdb . RetentionPolicy { } , fmt . Errorf ( "no retention policy" )
2014-12-30 22:46:33 +00:00
}
func ( testServerFailedRetention ) WriteSeries ( database , retentionPolicy , name string , tags map [ string ] string , timestamp time . Time , values map [ string ] interface { } ) error {
return nil
}
2014-12-31 21:37:58 +00:00
type testServerFailedWrite string
func ( testServerFailedWrite ) DefaultRetentionPolicy ( database string ) ( * influxdb . RetentionPolicy , error ) {
return & influxdb . RetentionPolicy { } , nil
2014-12-30 22:46:33 +00:00
}
func ( testServerFailedWrite ) WriteSeries ( database , retentionPolicy , name string , tags map [ string ] string , timestamp time . Time , values map [ string ] interface { } ) error {
return fmt . Errorf ( "failed write" )
}
2015-01-06 03:14:43 +00:00
func TestServer_ListenAndServeTCP_ErrBindAddressRequired ( t * testing . T ) {
2014-12-30 22:46:33 +00:00
var (
ts testServer
2014-12-31 21:37:58 +00:00
s = graphite . Server { Server : ts }
err = graphite . ErrBindAddressRequired
2015-01-06 03:14:43 +00:00
addr * net . TCPAddr
2014-12-30 22:46:33 +00:00
)
2015-01-06 03:14:43 +00:00
e := s . ListenAndServeTCP ( addr )
2014-12-30 22:46:33 +00:00
defer s . Close ( )
2014-12-31 21:37:58 +00:00
if e != err {
t . Fatalf ( "err does not match. expected %v, got %v" , err , e )
2014-12-30 22:46:33 +00:00
}
}
2015-01-06 03:14:43 +00:00
func TestServer_ListenAndServeTCP_ErrDatabaseNotSpecified ( t * testing . T ) {
2014-12-30 22:46:33 +00:00
var (
2015-01-06 03:14:43 +00:00
ts testServer
s = graphite . Server { Server : ts }
err = graphite . ErrDatabaseNotSpecified
2014-12-30 22:46:33 +00:00
)
2015-01-06 03:14:43 +00:00
addr := & net . TCPAddr { IP : net . ParseIP ( "127.0.0.1" ) }
2014-12-30 22:46:33 +00:00
2015-01-06 03:14:43 +00:00
e := s . ListenAndServeTCP ( addr )
2014-12-30 22:46:33 +00:00
defer s . Close ( )
2014-12-31 21:37:58 +00:00
if e != err {
t . Fatalf ( "err does not match. expected %v, got %v" , err , e )
2014-12-30 22:46:33 +00:00
}
}
2015-01-06 03:14:43 +00:00
func TestServer_ListenAndServeTCP_ErrServerNotSpecified ( t * testing . T ) {
2014-12-30 22:46:33 +00:00
var (
2015-01-06 03:14:43 +00:00
s = graphite . Server { }
err = graphite . ErrServerNotSpecified
2014-12-30 22:46:33 +00:00
)
s . Database = "foo"
2015-01-06 03:14:43 +00:00
addr := & net . TCPAddr { IP : net . ParseIP ( "127.0.0.1" ) }
2014-12-30 22:46:33 +00:00
2015-01-06 03:14:43 +00:00
e := s . ListenAndServeTCP ( addr )
2014-12-31 21:37:58 +00:00
defer s . Close ( )
if e != err {
t . Fatalf ( "err does not match. expected %v, got %v" , err , e )
}
}
2015-01-06 03:14:43 +00:00
func TestServer_ListenAndServeTCP_ValidRequest ( t * testing . T ) {
var (
ts testServer
s = graphite . Server { Server : ts }
addr = & net . TCPAddr { IP : net . ParseIP ( "127.0.0.1" ) , Port : 2004 }
)
s . Database = "foo"
s . ListenAndServeTCP ( addr )
defer s . Close ( )
// Connect to the graphite endpoint we just spun up
conn , err := net . Dial ( "tcp" , addr . String ( ) )
if err != nil {
t . Fatal ( err )
return
}
_ , err = conn . Write ( [ ] byte ( ` cpu 50.554 1419972457825\n ` ) )
defer conn . Close ( )
if err != nil {
t . Fatal ( err )
return
}
}
func TestServer_ListenAndServeUDP_ErrBindAddressRequired ( t * testing . T ) {
2014-12-31 21:37:58 +00:00
var (
ts testServer
s = graphite . Server { Server : ts }
2015-01-06 03:14:43 +00:00
err = graphite . ErrBindAddressRequired
addr * net . UDPAddr
)
e := s . ListenAndServeUDP ( addr )
defer s . Close ( )
if e != err {
t . Fatalf ( "err does not match. expected %v, got %v" , err , e )
}
}
func TestServer_ListenAndServeUDP_ErrDatabaseNotSpecified ( t * testing . T ) {
var (
ts testServer
s = graphite . Server { Server : ts }
err = graphite . ErrDatabaseNotSpecified
)
addr := & net . UDPAddr { IP : net . ParseIP ( "127.0.0.1" ) }
e := s . ListenAndServeUDP ( addr )
defer s . Close ( )
if e != err {
t . Fatalf ( "err does not match. expected %v, got %v" , err , e )
}
}
func TestServer_ListenAndServeUDP_ErrServerNotSpecified ( t * testing . T ) {
var (
s = graphite . Server { }
err = graphite . ErrServerNotSpecified
2014-12-31 21:37:58 +00:00
)
s . Database = "foo"
2015-01-06 03:14:43 +00:00
addr := & net . UDPAddr { IP : net . ParseIP ( "127.0.0.1" ) }
2014-12-31 21:37:58 +00:00
2015-01-06 03:14:43 +00:00
e := s . ListenAndServeUDP ( addr )
2014-12-30 22:46:33 +00:00
defer s . Close ( )
2015-01-06 03:14:43 +00:00
if e != err {
t . Fatalf ( "err does not match. expected %v, got %v" , err , e )
2014-12-30 22:46:33 +00:00
}
}
2014-12-31 21:37:58 +00:00
// Test Helpers
func errstr ( err error ) string {
if err != nil {
return err . Error ( )
}
return ""
}