2015-12-30 13:15:00 +00:00
package meta_test
2015-12-15 22:01:03 +00:00
import (
2016-01-06 20:10:26 +00:00
"encoding/json"
2015-12-15 22:01:03 +00:00
"io/ioutil"
2015-12-30 13:15:00 +00:00
"net"
2015-12-15 22:01:03 +00:00
"net/http"
"net/url"
2015-12-22 15:58:22 +00:00
"os"
"path"
2016-01-03 23:26:07 +00:00
"reflect"
2015-12-22 15:58:22 +00:00
"runtime"
2016-01-03 23:26:07 +00:00
"strings"
2016-01-02 20:12:54 +00:00
"sync"
2015-12-15 22:01:03 +00:00
"testing"
2015-12-30 21:17:52 +00:00
"time"
2015-12-22 15:58:22 +00:00
2015-12-30 13:15:00 +00:00
"github.com/influxdb/influxdb"
"github.com/influxdb/influxdb/influxql"
"github.com/influxdb/influxdb/services/meta"
"github.com/influxdb/influxdb/tcp"
2015-12-15 22:01:03 +00:00
)
2015-12-22 15:58:22 +00:00
// Test the ping endpoint.
2015-12-30 13:15:00 +00:00
func TestMetaService_PingEndpoint ( t * testing . T ) {
2015-12-22 15:58:22 +00:00
t . Parallel ( )
2015-12-15 22:01:03 +00:00
cfg := newConfig ( )
2015-12-22 15:58:22 +00:00
defer os . RemoveAll ( cfg . Dir )
2015-12-30 13:15:00 +00:00
s := newService ( cfg )
2015-12-15 22:01:03 +00:00
if err := s . Open ( ) ; err != nil {
t . Fatal ( err )
}
2015-12-30 13:15:00 +00:00
defer s . Close ( )
2015-12-15 22:01:03 +00:00
2016-01-02 20:12:54 +00:00
url , err := url . Parse ( s . HTTPAddr ( ) )
2015-12-15 22:01:03 +00:00
if err != nil {
t . Fatal ( err )
}
resp , err := http . Head ( "http://" + url . String ( ) + "/ping" )
if err != nil {
t . Fatal ( err )
}
defer resp . Body . Close ( )
2015-12-22 15:58:22 +00:00
if resp . StatusCode != http . StatusOK {
t . Fatalf ( "unexpected status:\n\texp: %d\n\tgot: %d\n" , http . StatusOK , resp . StatusCode )
}
_ , err = ioutil . ReadAll ( resp . Body )
2015-12-15 22:01:03 +00:00
if err != nil {
t . Fatal ( err )
}
if err := s . Close ( ) ; err != nil {
t . Fatal ( err )
}
}
2015-12-30 13:15:00 +00:00
func TestMetaService_CreateDatabase ( t * testing . T ) {
2015-12-30 21:17:52 +00:00
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
defer c . Close ( )
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE DATABASE db0" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
db , err := c . Database ( "db0" )
if err != nil {
2015-12-22 15:58:22 +00:00
t . Fatal ( err )
2015-12-30 21:17:52 +00:00
} else if db . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , db . Name )
2015-12-22 15:58:22 +00:00
}
2016-01-01 04:57:46 +00:00
// Make sure a default retention policy was created.
_ , err = c . RetentionPolicy ( "db0" , "default" )
if err != nil {
t . Fatal ( err )
} else if db . DefaultRetentionPolicy != "default" {
t . Fatalf ( "rp name wrong: %s" , db . DefaultRetentionPolicy )
}
2015-12-30 21:17:52 +00:00
}
func TestMetaService_CreateDatabaseIfNotExists ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
2015-12-30 13:15:00 +00:00
defer s . Close ( )
2015-12-30 21:17:52 +00:00
defer c . Close ( )
2015-12-22 15:58:22 +00:00
2015-12-30 21:17:52 +00:00
qry := ` CREATE DATABASE IF NOT EXISTS db0 `
if res := c . ExecuteStatement ( mustParseStatement ( qry ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
db , err := c . Database ( "db0" )
if err != nil {
t . Fatal ( err )
} else if db . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , db . Name )
}
if res := c . ExecuteStatement ( mustParseStatement ( qry ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
}
func TestMetaService_CreateDatabaseWithRetentionPolicy ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
defer c . Close ( )
qry := ` CREATE DATABASE db0 WITH DURATION 1h REPLICATION 1 NAME rp0 `
if res := c . ExecuteStatement ( mustParseStatement ( qry ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
db , err := c . Database ( "db0" )
if err != nil {
t . Fatal ( err )
} else if db . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , db . Name )
}
rp := db . RetentionPolicy ( "rp0" )
if err != nil {
t . Fatal ( err )
} else if rp . Name != "rp0" {
t . Fatalf ( "rp name wrong: %s" , rp . Name )
} else if rp . Duration != time . Hour {
t . Fatalf ( "rp duration wrong: %s" , rp . Duration . String ( ) )
} else if rp . ReplicaN != 1 {
t . Fatalf ( "rp replication wrong: %d" , rp . ReplicaN )
}
}
func TestMetaService_Databases ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
defer c . Close ( )
// Create two databases.
2016-01-01 00:18:13 +00:00
db , err := c . CreateDatabase ( "db0" )
2015-12-30 21:17:52 +00:00
if err != nil {
t . Fatalf ( err . Error ( ) )
} else if db . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , db . Name )
}
2016-01-01 00:18:13 +00:00
db , err = c . CreateDatabase ( "db1" )
2015-12-30 21:17:52 +00:00
if err != nil {
t . Fatalf ( err . Error ( ) )
} else if db . Name != "db1" {
t . Fatalf ( "db name wrong: %s" , db . Name )
}
dbs , err := c . Databases ( )
if err != nil {
2015-12-30 13:15:00 +00:00
t . Fatalf ( err . Error ( ) )
2015-12-22 15:58:22 +00:00
}
2015-12-30 21:17:52 +00:00
if len ( dbs ) != 2 {
t . Fatalf ( "expected 2 databases but got %d" , len ( dbs ) )
} else if dbs [ 0 ] . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , dbs [ 0 ] . Name )
} else if dbs [ 1 ] . Name != "db1" {
t . Fatalf ( "db name wrong: %s" , dbs [ 1 ] . Name )
}
}
func TestMetaService_DropDatabase ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
2015-12-30 13:15:00 +00:00
defer c . Close ( )
2015-12-22 15:58:22 +00:00
2015-12-30 21:17:52 +00:00
qry := ` CREATE DATABASE db0 `
if res := c . ExecuteStatement ( mustParseStatement ( qry ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
db , err := c . Database ( "db0" )
if err != nil {
t . Fatal ( err )
} else if db . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , db . Name )
}
qry = ` DROP DATABASE db0 `
if res := c . ExecuteStatement ( mustParseStatement ( qry ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
if _ , err = c . Database ( "db0" ) ; err == nil {
t . Fatal ( "expected an error" )
}
}
func TestMetaService_CreateRetentionPolicy ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
defer c . Close ( )
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE DATABASE db0" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
db , err := c . Database ( "db0" )
if err != nil {
t . Fatalf ( err . Error ( ) )
} else if db . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , db . Name )
}
qry := ` CREATE RETENTION POLICY rp0 ON db0 DURATION 1h REPLICATION 1 `
if res := c . ExecuteStatement ( mustParseStatement ( qry ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
rp , err := c . RetentionPolicy ( "db0" , "rp0" )
if err != nil {
t . Fatal ( err )
} else if rp . Name != "rp0" {
t . Fatalf ( "rp name wrong: %s" , rp . Name )
} else if rp . Duration != time . Hour {
t . Fatalf ( "rp duration wrong: %s" , rp . Duration . String ( ) )
} else if rp . ReplicaN != 1 {
t . Fatalf ( "rp replication wrong: %d" , rp . ReplicaN )
}
2016-01-01 00:18:13 +00:00
// Create the same policy. Should not error.
if res := c . ExecuteStatement ( mustParseStatement ( qry ) ) ; res . Err != nil {
2015-12-30 21:17:52 +00:00
t . Fatal ( res . Err )
}
2016-01-01 00:18:13 +00:00
rp , err = c . RetentionPolicy ( "db0" , "rp0" )
2015-12-30 21:17:52 +00:00
if err != nil {
t . Fatal ( err )
} else if rp . Name != "rp0" {
t . Fatalf ( "rp name wrong: %s" , rp . Name )
} else if rp . Duration != time . Hour {
t . Fatalf ( "rp duration wrong: %s" , rp . Duration . String ( ) )
} else if rp . ReplicaN != 1 {
t . Fatalf ( "rp replication wrong: %d" , rp . ReplicaN )
}
}
2016-01-01 04:57:46 +00:00
func TestMetaService_SetDefaultRetentionPolicy ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
defer c . Close ( )
qry := ` CREATE DATABASE db0 WITH DURATION 1h REPLICATION 1 NAME rp0 `
if res := c . ExecuteStatement ( mustParseStatement ( qry ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
db , err := c . Database ( "db0" )
if err != nil {
t . Fatalf ( err . Error ( ) )
} else if db . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , db . Name )
}
rp , err := c . RetentionPolicy ( "db0" , "rp0" )
if err != nil {
t . Fatal ( err )
} else if rp . Name != "rp0" {
t . Fatalf ( "rp name wrong: %s" , rp . Name )
} else if rp . Duration != time . Hour {
t . Fatalf ( "rp duration wrong: %s" , rp . Duration . String ( ) )
} else if rp . ReplicaN != 1 {
t . Fatalf ( "rp replication wrong: %d" , rp . ReplicaN )
}
// Make sure default retention policy hasn't been changed.
if db . DefaultRetentionPolicy != "default" {
t . Fatalf ( "rp name wrong: %s" , db . DefaultRetentionPolicy )
}
// Set the default retention policy to "rp0".
if err := c . SetDefaultRetentionPolicy ( "db0" , "rp0" ) ; err != nil {
t . Fatal ( err )
}
// Make sure the default retention policy changed to "rp1".
db , err = c . Database ( "db0" )
if err != nil {
t . Fatal ( err )
} else if db . DefaultRetentionPolicy != "rp0" {
t . Fatalf ( "rp name wrong: %s" , db . DefaultRetentionPolicy )
}
}
2015-12-30 21:17:52 +00:00
func TestMetaService_DropRetentionPolicy ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
defer c . Close ( )
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE DATABASE db0" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
2015-12-22 15:58:22 +00:00
}
2015-12-30 21:17:52 +00:00
db , err := c . Database ( "db0" )
if err != nil {
t . Fatalf ( err . Error ( ) )
} else if db . Name != "db0" {
2015-12-30 13:15:00 +00:00
t . Fatalf ( "db name wrong: %s" , db . Name )
2015-12-22 15:58:22 +00:00
}
2015-12-30 21:17:52 +00:00
qry := ` CREATE RETENTION POLICY rp0 ON db0 DURATION 1h REPLICATION 1 `
if res := c . ExecuteStatement ( mustParseStatement ( qry ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
rp , err := c . RetentionPolicy ( "db0" , "rp0" )
if err != nil {
t . Fatal ( err )
} else if rp . Name != "rp0" {
t . Fatalf ( "rp name wrong: %s" , rp . Name )
} else if rp . Duration != time . Hour {
t . Fatalf ( "rp duration wrong: %s" , rp . Duration . String ( ) )
} else if rp . ReplicaN != 1 {
t . Fatalf ( "rp replication wrong: %d" , rp . ReplicaN )
}
qry = ` DROP RETENTION POLICY rp0 ON db0 `
if res := c . ExecuteStatement ( mustParseStatement ( qry ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
rp , err = c . RetentionPolicy ( "db0" , "rp0" )
if err != nil {
t . Fatal ( err )
} else if rp != nil {
t . Fatalf ( "rp should have been dropped" )
}
}
2016-01-05 20:06:23 +00:00
func TestMetaService_CreateUser ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
defer c . Close ( )
// Create an admin user
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE USER fred WITH PASSWORD 'supersecure' WITH ALL PRIVILEGES" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
// Create a non-admin user
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE USER wilma WITH PASSWORD 'password'" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
u , err := c . User ( "fred" )
if err != nil {
t . Fatal ( err )
}
if exp , got := "fred" , u . Name ; exp != got {
t . Fatalf ( "unexpected user name: exp: %s got: %s" , exp , got )
}
if ! u . Admin {
t . Fatalf ( "expected user to be admin" )
}
u , err = c . Authenticate ( "fred" , "supersecure" )
if u == nil || err != nil {
t . Fatalf ( "failed to authenticate" )
}
if u . Name != "fred" {
t . Fatalf ( "failed to authenticate" )
}
// Auth for bad password should fail
u , err = c . Authenticate ( "fred" , "badpassword" )
if u != nil || err != meta . ErrAuthenticate {
t . Fatalf ( "authentication should fail with %s" , meta . ErrAuthenticate )
}
// Auth for no password should fail
u , err = c . Authenticate ( "fred" , "" )
if u != nil || err != meta . ErrAuthenticate {
t . Fatalf ( "authentication should fail with %s" , meta . ErrAuthenticate )
}
// Auth for unkonwn user should fail
u , err = c . Authenticate ( "foo" , "" )
if u != nil || err != meta . ErrUserNotFound {
t . Fatalf ( "authentication should fail with %s" , meta . ErrUserNotFound )
}
u , err = c . User ( "wilma" )
if err != nil {
t . Fatal ( err )
}
if exp , got := "wilma" , u . Name ; exp != got {
t . Fatalf ( "unexpected user name: exp: %s got: %s" , exp , got )
}
if u . Admin {
t . Fatalf ( "expected user not to be an admin" )
}
if exp , got := 2 , c . UserCount ( ) ; exp != got {
t . Fatalf ( "unexpected user count. got: %d exp: %d" , got , exp )
}
// Grant privilidges to a non-admin user
if res := c . ExecuteStatement ( mustParseStatement ( "GRANT ALL PRIVILEGES TO wilma" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
u , err = c . User ( "wilma" )
if err != nil {
t . Fatal ( err )
}
if exp , got := "wilma" , u . Name ; exp != got {
t . Fatalf ( "unexpected user name: exp: %s got: %s" , exp , got )
}
if ! u . Admin {
t . Fatalf ( "expected user to be an admin" )
}
// Revoke privilidges from user
if res := c . ExecuteStatement ( mustParseStatement ( "REVOKE ALL PRIVILEGES FROM wilma" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
u , err = c . User ( "wilma" )
if err != nil {
t . Fatal ( err )
}
if exp , got := "wilma" , u . Name ; exp != got {
t . Fatalf ( "unexpected user name: exp: %s got: %s" , exp , got )
}
if u . Admin {
t . Fatalf ( "expected user not to be an admin" )
}
// Revoke privilidges from user
if res := c . ExecuteStatement ( mustParseStatement ( "REVOKE ALL PRIVILEGES FROM wilma" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
u , err = c . User ( "wilma" )
if err != nil {
t . Fatal ( err )
}
if exp , got := "wilma" , u . Name ; exp != got {
t . Fatalf ( "unexpected user name: exp: %s got: %s" , exp , got )
}
if u . Admin {
t . Fatalf ( "expected user not to be an admin" )
}
// Create a database to use for assiging privileges to.
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE DATABASE db0" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
db , err := c . Database ( "db0" )
if err != nil {
t . Fatal ( err )
} else if db . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , db . Name )
}
// Assign a single privilege at the database level
if res := c . ExecuteStatement ( mustParseStatement ( "GRANT READ ON db0 TO wilma" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
p , err := c . UserPrivilege ( "wilma" , "db0" )
if err != nil {
t . Fatal ( err )
}
if p == nil {
t . Fatal ( "expected privilege but was nil" )
}
if exp , got := influxql . ReadPrivilege , * p ; exp != got {
t . Fatalf ( "unexpected privilege. exp: %d, got: %d" , exp , got )
}
// Remove a single privilege at the database level
if res := c . ExecuteStatement ( mustParseStatement ( "REVOKE READ ON db0 FROM wilma" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
p , err = c . UserPrivilege ( "wilma" , "db0" )
if err != nil {
t . Fatal ( err )
}
if p == nil {
t . Fatal ( "expected privilege but was nil" )
}
if exp , got := influxql . NoPrivileges , * p ; exp != got {
t . Fatalf ( "unexpected privilege. exp: %d, got: %d" , exp , got )
}
// Drop a user
if res := c . ExecuteStatement ( mustParseStatement ( "DROP USER wilma" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
u , err = c . User ( "wilma" )
if err != meta . ErrUserNotFound {
t . Fatalf ( "user lookup should fail with %s" , meta . ErrUserNotFound )
}
if exp , got := 1 , c . UserCount ( ) ; exp != got {
t . Fatalf ( "unexpected user count. got: %d exp: %d" , got , exp )
}
}
2016-01-06 20:10:26 +00:00
func TestMetaService_ContinuousQueries ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
defer c . Close ( )
// Create a database to use
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE DATABASE db0" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
db , err := c . Database ( "db0" )
if err != nil {
t . Fatal ( err )
} else if db . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , db . Name )
}
// Create a CQ
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE CONTINUOUS QUERY cq0 ON db0 BEGIN SELECT count(value) INTO foo_count FROM foo GROUP BY time(10m) END" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
res := c . ExecuteStatement ( mustParseStatement ( "SHOW CONTINUOUS QUERIES" ) )
if res . Err != nil {
t . Fatal ( res . Err )
}
exp := ` { "series":[ { "name":"db0","columns":["name","query"],"values":[["cq0","CREATE CONTINUOUS QUERY cq0 ON db0 BEGIN SELECT count(value) INTO foo_count FROM foo GROUP BY time(10m) END"]]}]} `
got := mustMarshalJSON ( res )
if exp != got {
t . Fatalf ( "unexpected response.\n\nexp: %s\ngot: %s\n" , exp , got )
}
// Recreate an existing CQ
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE CONTINUOUS QUERY cq0 ON db0 BEGIN SELECT max(value) INTO foo_max FROM foo GROUP BY time(10m) END" ) ) ; res . Err == nil {
t . Fatalf ( "expected error: got %v" , res . Err )
}
// Create a few more CQ's
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE CONTINUOUS QUERY cq1 ON db0 BEGIN SELECT max(value) INTO foo_max FROM foo GROUP BY time(10m) END" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE CONTINUOUS QUERY cq2 ON db0 BEGIN SELECT min(value) INTO foo_min FROM foo GROUP BY time(10m) END" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
// Drop a single CQ
if res := c . ExecuteStatement ( mustParseStatement ( "DROP CONTINUOUS QUERY cq1 ON db0" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
res = c . ExecuteStatement ( mustParseStatement ( "SHOW CONTINUOUS QUERIES" ) )
if res . Err != nil {
t . Fatal ( res . Err )
}
exp = ` { "series":[ { "name":"db0","columns":["name","query"],"values":[["cq0","CREATE CONTINUOUS QUERY cq0 ON db0 BEGIN SELECT count(value) INTO foo_count FROM foo GROUP BY time(10m) END"],["cq2","CREATE CONTINUOUS QUERY cq2 ON db0 BEGIN SELECT min(value) INTO foo_min FROM foo GROUP BY time(10m) END"]]}]} `
got = mustMarshalJSON ( res )
if exp != got {
t . Fatalf ( "unexpected response.\n\nexp: %s\ngot: %s\n" , exp , got )
}
}
2016-01-06 21:43:48 +00:00
func TestMetaService_Subscriptions ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
defer c . Close ( )
// Create a database to use
if res := c . ExecuteStatement ( mustParseStatement ( "CREATE DATABASE db0" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
db , err := c . Database ( "db0" )
if err != nil {
t . Fatal ( err )
} else if db . Name != "db0" {
t . Fatalf ( "db name wrong: %s" , db . Name )
}
// Create a subscription
if res := c . ExecuteStatement ( mustParseStatement ( ` CREATE SUBSCRIPTION sub0 ON db0."default" DESTINATIONS ALL 'udp://example.com:9090' ` ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
// Re-create a subscription
if res := c . ExecuteStatement ( mustParseStatement ( ` CREATE SUBSCRIPTION sub0 ON db0."default" DESTINATIONS ALL 'udp://example.com:9090' ` ) ) ; res . Err == nil {
t . Fatal ( res . Err )
}
res := c . ExecuteStatement ( mustParseStatement ( ` SHOW SUBSCRIPTIONS ` ) )
if res . Err != nil {
t . Fatal ( res . Err )
}
exp := ` { "series":[ { "name":"db0","columns":["retention_policy","name","mode","destinations"],"values":[["default","sub0","ALL",["udp://example.com:9090"]]]}]} `
got := mustMarshalJSON ( res )
if exp != got {
t . Fatalf ( "unexpected response.\n\nexp: %s\ngot: %s\n" , exp , got )
}
// Create a couple more subscriptions
if res := c . ExecuteStatement ( mustParseStatement ( ` CREATE SUBSCRIPTION sub1 ON db0."default" DESTINATIONS ALL 'udp://example.com:6060' ` ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
if res := c . ExecuteStatement ( mustParseStatement ( ` CREATE SUBSCRIPTION sub2 ON db0."default" DESTINATIONS ALL 'udp://example.com:7070' ` ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
// Re-create a subscription
if res := c . ExecuteStatement ( mustParseStatement ( ` DROP SUBSCRIPTION sub1 ON db0."default" ` ) ) ; res . Err != nil {
t . Fatal ( res . Err )
}
res = c . ExecuteStatement ( mustParseStatement ( ` SHOW SUBSCRIPTIONS ` ) )
if res . Err != nil {
t . Fatal ( res . Err )
}
exp = ` { "series":[ { "name":"db0","columns":["retention_policy","name","mode","destinations"],"values":[["default","sub0","ALL",["udp://example.com:9090"]],["default","sub2","ALL",["udp://example.com:7070"]]]}]} `
got = mustMarshalJSON ( res )
if exp != got {
t . Fatalf ( "unexpected response.\n\nexp: %s\ngot: %s\n" , exp , got )
}
}
2015-12-30 13:15:00 +00:00
func TestMetaService_CreateRemoveMetaNode ( t * testing . T ) {
2015-12-30 22:52:39 +00:00
t . Parallel ( )
2015-12-30 13:15:00 +00:00
cfg1 := newConfig ( )
defer os . RemoveAll ( cfg1 . Dir )
cfg2 := newConfig ( )
defer os . RemoveAll ( cfg2 . Dir )
cfg3 := newConfig ( )
defer os . RemoveAll ( cfg3 . Dir )
cfg4 := newConfig ( )
defer os . RemoveAll ( cfg4 . Dir )
s1 := newService ( cfg1 )
if err := s1 . Open ( ) ; err != nil {
t . Fatalf ( err . Error ( ) )
}
defer s1 . Close ( )
2016-01-02 20:12:54 +00:00
cfg2 . JoinPeers = [ ] string { s1 . HTTPAddr ( ) }
2015-12-30 13:15:00 +00:00
s2 := newService ( cfg2 )
if err := s2 . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
defer s2 . Close ( )
func ( ) {
2016-01-02 20:12:54 +00:00
cfg3 . JoinPeers = [ ] string { s2 . HTTPAddr ( ) }
2015-12-30 13:15:00 +00:00
s3 := newService ( cfg3 )
if err := s3 . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
defer s3 . Close ( )
2015-12-22 15:58:22 +00:00
2016-01-02 20:12:54 +00:00
c1 := meta . NewClient ( [ ] string { s1 . HTTPAddr ( ) } , false )
2015-12-30 13:15:00 +00:00
if err := c1 . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
defer c1 . Close ( )
2015-12-22 15:58:22 +00:00
2015-12-30 13:15:00 +00:00
metaNodes , _ := c1 . MetaNodes ( )
if len ( metaNodes ) != 3 {
t . Fatalf ( "meta nodes wrong: %v" , metaNodes )
}
} ( )
2015-12-22 15:58:22 +00:00
2016-01-02 20:12:54 +00:00
c := meta . NewClient ( [ ] string { s1 . HTTPAddr ( ) } , false )
2015-12-30 13:15:00 +00:00
if err := c . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
2015-12-22 15:58:22 +00:00
}
2015-12-30 13:15:00 +00:00
defer c . Close ( )
2015-12-22 15:58:22 +00:00
2015-12-30 13:15:00 +00:00
if res := c . ExecuteStatement ( mustParseStatement ( "DROP META SERVER 3" ) ) ; res . Err != nil {
t . Fatal ( res . Err )
2015-12-22 15:58:22 +00:00
}
2015-12-30 13:15:00 +00:00
metaNodes , _ := c . MetaNodes ( )
if len ( metaNodes ) != 2 {
t . Fatalf ( "meta nodes wrong: %v" , metaNodes )
2015-12-22 15:58:22 +00:00
}
2016-01-02 20:12:54 +00:00
cfg4 . JoinPeers = [ ] string { s1 . HTTPAddr ( ) }
2015-12-30 13:15:00 +00:00
s4 := newService ( cfg4 )
if err := s4 . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
2015-12-22 15:58:22 +00:00
}
2015-12-30 13:15:00 +00:00
defer s4 . Close ( )
2015-12-22 15:58:22 +00:00
2015-12-30 13:15:00 +00:00
metaNodes , _ = c . MetaNodes ( )
if len ( metaNodes ) != 3 {
t . Fatalf ( "meta nodes wrong: %v" , metaNodes )
2015-12-22 15:58:22 +00:00
}
2015-12-30 13:15:00 +00:00
}
2015-12-22 15:58:22 +00:00
2015-12-30 13:15:00 +00:00
// Ensure that if we attempt to create a database and the client
// is pointed at a server that isn't the leader, it automatically
// hits the leader and finishes the command
func TestMetaService_CommandAgainstNonLeader ( t * testing . T ) {
2015-12-30 22:52:39 +00:00
t . Parallel ( )
cfgs := make ( [ ] * meta . Config , 3 )
2016-01-02 20:12:54 +00:00
srvs := make ( [ ] * testService , 3 )
2015-12-30 22:52:39 +00:00
for i , _ := range cfgs {
c := newConfig ( )
cfgs [ i ] = c
if i > 0 {
2016-01-02 20:12:54 +00:00
c . JoinPeers = [ ] string { srvs [ 0 ] . HTTPAddr ( ) }
2015-12-30 22:52:39 +00:00
}
srvs [ i ] = newService ( c )
if err := srvs [ i ] . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
defer srvs [ i ] . Close ( )
2016-01-02 20:12:54 +00:00
defer os . RemoveAll ( c . Dir )
2015-12-30 22:52:39 +00:00
}
2016-01-02 20:12:54 +00:00
c := meta . NewClient ( [ ] string { srvs [ 2 ] . HTTPAddr ( ) } , false )
2015-12-30 22:52:39 +00:00
if err := c . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
2016-01-02 20:12:54 +00:00
defer c . Close ( )
2015-12-30 22:52:39 +00:00
metaNodes , _ := c . MetaNodes ( )
if len ( metaNodes ) != 3 {
t . Fatalf ( "meta nodes wrong: %v" , metaNodes )
}
2015-12-22 15:58:22 +00:00
2016-01-01 00:18:13 +00:00
if _ , err := c . CreateDatabase ( "foo" ) ; err != nil {
2015-12-30 22:52:39 +00:00
t . Fatal ( err )
}
if db , err := c . Database ( "foo" ) ; db == nil || err != nil {
t . Fatalf ( "database foo wasn't created: %s" , err . Error ( ) )
}
2015-12-22 15:58:22 +00:00
}
2015-12-15 22:01:03 +00:00
2016-01-02 20:12:54 +00:00
// Ensure that the client will fail over to another server if the leader goes
// down. Also ensure that the cluster will come back up successfully after restart
func TestMetaService_FailureAndRestartCluster ( t * testing . T ) {
t . Parallel ( )
cfgs := make ( [ ] * meta . Config , 3 )
srvs := make ( [ ] * testService , 3 )
for i , _ := range cfgs {
c := newConfig ( )
cfgs [ i ] = c
if i > 0 {
c . JoinPeers = [ ] string { srvs [ 0 ] . HTTPAddr ( ) }
}
srvs [ i ] = newService ( c )
if err := srvs [ i ] . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
c . HTTPBindAddress = srvs [ i ] . HTTPAddr ( )
c . BindAddress = srvs [ i ] . RaftAddr ( )
c . JoinPeers = nil
defer srvs [ i ] . Close ( )
defer os . RemoveAll ( c . Dir )
}
c := meta . NewClient ( [ ] string { srvs [ 0 ] . HTTPAddr ( ) , srvs [ 1 ] . HTTPAddr ( ) } , false )
if err := c . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
defer c . Close ( )
if _ , err := c . CreateDatabase ( "foo" ) ; err != nil {
t . Fatal ( err )
}
if db , err := c . Database ( "foo" ) ; db == nil || err != nil {
t . Fatalf ( "database foo wasn't created: %s" , err . Error ( ) )
}
if err := srvs [ 0 ] . Close ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
if _ , err := c . CreateDatabase ( "bar" ) ; err != nil {
t . Fatal ( err )
}
if db , err := c . Database ( "bar" ) ; db == nil || err != nil {
t . Fatalf ( "database bar wasn't created: %s" , err . Error ( ) )
}
if err := srvs [ 1 ] . Close ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
if err := srvs [ 2 ] . Close ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
// give them a second to shut down
time . Sleep ( time . Second )
// when we start back up they need to happen simultaneously, otherwise
// a leader won't get elected
var wg sync . WaitGroup
for i , cfg := range cfgs {
srvs [ i ] = newService ( cfg )
wg . Add ( 1 )
go func ( srv * testService ) {
if err := srv . Open ( ) ; err != nil {
panic ( err )
}
wg . Done ( )
} ( srvs [ i ] )
defer srvs [ i ] . Close ( )
}
wg . Wait ( )
time . Sleep ( time . Second )
c2 := meta . NewClient ( [ ] string { srvs [ 0 ] . HTTPAddr ( ) } , false )
if err := c2 . Open ( ) ; err != nil {
t . Fatal ( err )
}
defer c2 . Close ( )
if db , err := c2 . Database ( "bar" ) ; db == nil || err != nil {
t . Fatalf ( "database bar wasn't created: %s" , err . Error ( ) )
}
if _ , err := c2 . CreateDatabase ( "asdf" ) ; err != nil {
t . Fatal ( err )
}
if db , err := c2 . Database ( "asdf" ) ; db == nil || err != nil {
t . Fatalf ( "database bar wasn't created: %s" , err . Error ( ) )
}
}
2016-01-03 23:26:07 +00:00
// Ensures that everything works after a host name change. This is
// skipped by default. To enable add hosts foobar and asdf to your
// /etc/hosts file and point those to 127.0.0.1
func TestMetaService_NameChangeSingleNode ( t * testing . T ) {
t . Skip ( "not enabled" )
t . Parallel ( )
cfg := newConfig ( )
defer os . RemoveAll ( cfg . Dir )
cfg . BindAddress = "foobar:0"
cfg . HTTPBindAddress = "foobar:0"
s := newService ( cfg )
if err := s . Open ( ) ; err != nil {
t . Fatal ( err )
}
defer s . Close ( )
c := meta . NewClient ( [ ] string { s . HTTPAddr ( ) } , false )
if err := c . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
defer c . Close ( )
if _ , err := c . CreateDatabase ( "foo" ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
s . Close ( )
time . Sleep ( time . Second )
cfg . BindAddress = "asdf" + ":" + strings . Split ( s . RaftAddr ( ) , ":" ) [ 1 ]
cfg . HTTPBindAddress = "asdf" + ":" + strings . Split ( s . HTTPAddr ( ) , ":" ) [ 1 ]
s = newService ( cfg )
if err := s . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
defer s . Close ( )
c2 := meta . NewClient ( [ ] string { s . HTTPAddr ( ) } , false )
if err := c2 . Open ( ) ; err != nil {
t . Fatal ( err . Error ( ) )
}
defer c2 . Close ( )
db , err := c2 . Database ( "foo" )
if db == nil || err != nil {
t . Fatal ( err . Error ( ) )
}
nodes , err := c2 . MetaNodes ( )
if err != nil {
t . Fatal ( err . Error ( ) )
}
exp := [ ] meta . NodeInfo { { ID : 1 , Host : cfg . HTTPBindAddress , TCPHost : cfg . BindAddress } }
time . Sleep ( 10 * time . Second )
if ! reflect . DeepEqual ( nodes , exp ) {
t . Fatalf ( "nodes don't match: %v" , nodes )
}
}
2016-01-05 15:36:37 +00:00
func TestMetaService_CreateDataNode ( t * testing . T ) {
t . Parallel ( )
d , s , c := newServiceAndClient ( )
defer os . RemoveAll ( d )
defer s . Close ( )
defer c . Close ( )
exp := & meta . NodeInfo {
ID : 2 ,
Host : "foo:8180" ,
TCPHost : "bar:8281" ,
}
n , err := c . CreateDataNode ( exp . Host , exp . TCPHost )
if err != nil {
t . Fatal ( err . Error ( ) )
}
if ! reflect . DeepEqual ( n , exp ) {
t . Fatalf ( "data node attributes wrong: %v" , n )
}
nodes , err := c . DataNodes ( )
if err != nil {
t . Fatal ( err . Error ( ) )
}
if ! reflect . DeepEqual ( nodes , [ ] meta . NodeInfo { * exp } ) {
t . Fatalf ( "nodes wrong: %v" , nodes )
}
}
2016-01-02 20:12:54 +00:00
// newServiceAndClient returns new data directory, *Service, and *Client or panics.
// Caller is responsible for deleting data dir and closing client.
func newServiceAndClient ( ) ( string , * testService , * meta . Client ) {
cfg := newConfig ( )
s := newService ( cfg )
if err := s . Open ( ) ; err != nil {
panic ( err )
}
c := meta . NewClient ( [ ] string { s . HTTPAddr ( ) } , false )
if err := c . Open ( ) ; err != nil {
panic ( err )
}
return cfg . Dir , s , c
}
2015-12-30 13:15:00 +00:00
func newConfig ( ) * meta . Config {
cfg := meta . NewConfig ( )
cfg . BindAddress = "127.0.0.1:0"
cfg . HTTPBindAddress = "127.0.0.1:0"
2015-12-22 15:58:22 +00:00
cfg . Dir = testTempDir ( 2 )
2015-12-15 22:01:03 +00:00
return cfg
}
2015-12-22 15:58:22 +00:00
func testTempDir ( skip int ) string {
// Get name of the calling function.
pc , _ , _ , ok := runtime . Caller ( skip )
if ! ok {
panic ( "failed to get name of test function" )
}
_ , prefix := path . Split ( runtime . FuncForPC ( pc ) . Name ( ) )
// Make a temp dir prefixed with calling function's name.
dir , err := ioutil . TempDir ( "/tmp" , prefix )
if err != nil {
panic ( err )
}
return dir
}
2016-01-02 20:12:54 +00:00
type testService struct {
* meta . Service
ln net . Listener
}
func ( t * testService ) Close ( ) error {
if err := t . Service . Close ( ) ; err != nil {
return err
}
return t . ln . Close ( )
}
func newService ( cfg * meta . Config ) * testService {
2015-12-30 13:15:00 +00:00
// Open shared TCP connection.
ln , err := net . Listen ( "tcp" , cfg . BindAddress )
2015-12-22 15:58:22 +00:00
if err != nil {
panic ( err )
}
2015-12-30 13:15:00 +00:00
// Multiplex listener.
mux := tcp . NewMux ( )
s := meta . NewService ( cfg , & influxdb . Node { } )
s . RaftListener = mux . Listen ( meta . MuxHeader )
go mux . Serve ( ln )
2016-01-02 20:12:54 +00:00
return & testService { Service : s , ln : ln }
2015-12-22 15:58:22 +00:00
}
2015-12-30 13:15:00 +00:00
func mustParseStatement ( s string ) influxql . Statement {
stmt , err := influxql . ParseStatement ( s )
2015-12-22 15:58:22 +00:00
if err != nil {
2015-12-30 13:15:00 +00:00
panic ( err )
2015-12-22 15:58:22 +00:00
}
2015-12-30 13:15:00 +00:00
return stmt
2015-12-22 15:58:22 +00:00
}
2016-01-06 20:10:26 +00:00
func mustMarshalJSON ( v interface { } ) string {
b , e := json . Marshal ( v )
if e != nil {
panic ( e )
}
return string ( b )
}