2015-05-20 20:57:04 +00:00
package meta_test
2015-05-21 20:06:01 +00:00
// import "github.com/davecgh/go-spew/spew"
2015-05-20 20:57:04 +00:00
import (
2015-05-21 20:06:01 +00:00
"fmt"
2015-05-20 20:57:04 +00:00
"reflect"
"testing"
"time"
2015-06-08 19:07:05 +00:00
"github.com/davecgh/go-spew/spew"
2015-08-31 22:03:44 +00:00
"github.com/gogo/protobuf/proto"
2015-05-20 20:57:04 +00:00
"github.com/influxdb/influxdb/influxql"
"github.com/influxdb/influxdb/meta"
2015-08-31 22:03:44 +00:00
"github.com/influxdb/influxdb/meta/internal"
2015-05-20 20:57:04 +00:00
)
2015-05-21 20:06:01 +00:00
// Ensure a node can be created.
func TestData_CreateNode ( t * testing . T ) {
var data meta . Data
if err := data . CreateNode ( "host0" ) ; err != nil {
t . Fatal ( err )
} else if ! reflect . DeepEqual ( data . Nodes , [ ] meta . NodeInfo { { ID : 1 , Host : "host0" } } ) {
t . Fatalf ( "unexpected node: %#v" , data . Nodes [ 0 ] )
}
}
// Ensure a node can be removed.
2015-10-03 02:49:11 +00:00
func TestData_DeleteNode_Basic ( t * testing . T ) {
2015-05-21 20:06:01 +00:00
var data meta . Data
if err := data . CreateNode ( "host0" ) ; err != nil {
t . Fatal ( err )
} else if err = data . CreateNode ( "host1" ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateNode ( "host2" ) ; err != nil {
t . Fatal ( err )
}
2015-10-03 02:49:11 +00:00
if err := data . DeleteNode ( 1 , false ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
} else if len ( data . Nodes ) != 2 {
t . Fatalf ( "unexpected node count: %d" , len ( data . Nodes ) )
} else if data . Nodes [ 0 ] != ( meta . NodeInfo { ID : 2 , Host : "host1" } ) {
t . Fatalf ( "unexpected node: %#v" , data . Nodes [ 0 ] )
} else if data . Nodes [ 1 ] != ( meta . NodeInfo { ID : 3 , Host : "host2" } ) {
t . Fatalf ( "unexpected node: %#v" , data . Nodes [ 1 ] )
}
}
2015-10-03 02:49:11 +00:00
// Ensure a node can be removed with shard info in play
func TestData_DeleteNode_Shards ( t * testing . T ) {
var data meta . Data
if err := data . CreateNode ( "host0" ) ; err != nil {
t . Fatal ( err )
} else if err = data . CreateNode ( "host1" ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateNode ( "host2" ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateNode ( "host3" ) ; err != nil {
t . Fatal ( err )
}
if err := data . CreateDatabase ( "mydb" ) ; err != nil {
t . Fatal ( err )
}
rpi := & meta . RetentionPolicyInfo {
Name : "myrp" ,
ReplicaN : 3 ,
}
if err := data . CreateRetentionPolicy ( "mydb" , rpi ) ; err != nil {
t . Fatal ( err )
}
if err := data . CreateShardGroup ( "mydb" , "myrp" , time . Now ( ) ) ; err != nil {
t . Fatal ( err )
}
if len ( data . Databases [ 0 ] . RetentionPolicies [ 0 ] . ShardGroups [ 0 ] . Shards [ 0 ] . Owners ) != 3 {
t . Fatal ( "wrong number of shard owners" )
}
if err := data . DeleteNode ( 2 , false ) ; err != nil {
t . Fatal ( err )
}
if got , exp := len ( data . Databases [ 0 ] . RetentionPolicies [ 0 ] . ShardGroups [ 0 ] . Shards [ 0 ] . Owners ) , 2 ; exp != got {
t . Fatalf ( "wrong number of shard owners, got %d, exp %d" , got , exp )
}
for _ , s := range data . Databases [ 0 ] . RetentionPolicies [ 0 ] . ShardGroups [ 0 ] . Shards {
if s . OwnedBy ( 2 ) {
t . Fatal ( "shard still owned by delted node" )
}
}
}
2015-05-21 20:06:01 +00:00
// Ensure a database can be created.
func TestData_CreateDatabase ( t * testing . T ) {
var data meta . Data
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
} else if ! reflect . DeepEqual ( data . Databases , [ ] meta . DatabaseInfo { { Name : "db0" } } ) {
t . Fatalf ( "unexpected databases: %#v" , data . Databases )
}
}
// Ensure that creating a database without a name returns an error.
func TestData_CreateDatabase_ErrNameRequired ( t * testing . T ) {
var data meta . Data
if err := data . CreateDatabase ( "" ) ; err != meta . ErrDatabaseNameRequired {
t . Fatalf ( "unexpected error: %s" , err )
}
}
// Ensure that creating an already existing database returns an error.
func TestData_CreateDatabase_ErrDatabaseExists ( t * testing . T ) {
var data meta . Data
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
}
if err := data . CreateDatabase ( "db0" ) ; err != meta . ErrDatabaseExists {
t . Fatalf ( "unexpected error: %s" , err )
}
}
// Ensure a database can be removed.
func TestData_DropDatabase ( t * testing . T ) {
var data meta . Data
for i := 0 ; i < 3 ; i ++ {
if err := data . CreateDatabase ( fmt . Sprintf ( "db%d" , i ) ) ; err != nil {
t . Fatal ( err )
}
}
if err := data . DropDatabase ( "db1" ) ; err != nil {
t . Fatal ( err )
} else if ! reflect . DeepEqual ( data . Databases , [ ] meta . DatabaseInfo { { Name : "db0" } , { Name : "db2" } } ) {
t . Fatalf ( "unexpected databases: %#v" , data . Databases )
}
}
2015-09-21 18:59:12 +00:00
// Ensure a database can be renamed.
func TestData_RenameDatabase ( t * testing . T ) {
var data meta . Data
for i := 0 ; i < 2 ; i ++ {
if err := data . CreateDatabase ( fmt . Sprintf ( "db%d" , i ) ) ; err != nil {
t . Fatal ( err )
}
}
if err := data . RenameDatabase ( "db1" , "db2" ) ; err != nil {
t . Fatal ( err )
} else if ! reflect . DeepEqual ( data . Databases , [ ] meta . DatabaseInfo { { Name : "db0" } , { Name : "db2" } } ) {
t . Fatalf ( "unexpected databases: %#v" , data . Databases )
}
}
2015-10-07 02:01:53 +00:00
// Ensure that user privileges are updated correctly when database is renamed.
func TestData_RenameDatabaseUpdatesPrivileges ( t * testing . T ) {
var data meta . Data
for i := 0 ; i < 2 ; i ++ {
if err := data . CreateDatabase ( fmt . Sprintf ( "db%d" , i ) ) ; err != nil {
t . Fatal ( err )
}
}
data . Users = [ ] meta . UserInfo { {
Name : "susy" ,
Hash : "ABC123" ,
Admin : true ,
Privileges : map [ string ] influxql . Privilege {
"db1" : influxql . AllPrivileges , "db0" : influxql . ReadPrivilege } } }
if err := data . RenameDatabase ( "db1" , "db2" ) ; err != nil {
t . Fatal ( err )
} else if ! reflect . DeepEqual ( data . Users ,
[ ] meta . UserInfo { {
Name : "susy" ,
Hash : "ABC123" ,
Admin : true ,
Privileges : map [ string ] influxql . Privilege {
"db2" : influxql . AllPrivileges , "db0" : influxql . ReadPrivilege } } } ) {
t . Fatalf ( "unexpected user privileges: %#v" , data . Users )
}
}
2015-09-21 18:59:12 +00:00
// Ensure that renaming a database without both old and new names returns an error.
func TestData_RenameDatabase_ErrNameRequired ( t * testing . T ) {
var data meta . Data
if err := data . RenameDatabase ( "" , "" ) ; err != meta . ErrDatabaseNameRequired {
t . Fatalf ( "unexpected error: %s" , err )
}
if err := data . RenameDatabase ( "from_foo" , "" ) ; err != meta . ErrDatabaseNameRequired {
t . Fatalf ( "unexpected error: %s" , err )
}
if err := data . RenameDatabase ( "" , "to_foo" ) ; err != meta . ErrDatabaseNameRequired {
t . Fatalf ( "unexpected error: %s" , err )
}
}
2015-10-09 17:36:01 +00:00
// Ensure that renaming a database returns an error if there is a possibly conflicting CQ
func TestData_RenameDatabase_ErrDatabaseCQConflict ( t * testing . T ) {
var data meta . Data
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateDatabase ( "db1" ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateContinuousQuery ( "db0" , "cq0" , ` CREATE CONTINUOUS QUERY cq0 ON db0 BEGIN SELECT count() INTO "foo"."default"."bar" FROM "foo"."foobar" END ` ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateContinuousQuery ( "db1" , "cq1" , ` CREATE CONTINUOUS QUERY cq1 ON db1 BEGIN SELECT count() INTO "db1"."default"."bar" FROM "db0"."foobar" END ` ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateContinuousQuery ( "db1" , "cq2" , ` CREATE CONTINUOUS QUERY cq2 ON db1 BEGIN SELECT count() INTO "db0"."default"."bar" FROM "db1"."foobar" END ` ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateContinuousQuery ( "db1" , "noconflict" , ` CREATE CONTINUOUS QUERY noconflict ON db1 BEGIN SELECT count() INTO "db1"."default"."bar" FROM "db1"."foobar" END ` ) ; err != nil {
t . Fatal ( err )
} else if err := data . RenameDatabase ( "db0" , "db2" ) ; err == nil {
t . Fatalf ( "unexpected rename database success despite cq conflict" )
} else if err := data . DropContinuousQuery ( "db0" , "cq0" ) ; err != nil {
t . Fatal ( err )
} else if err := data . RenameDatabase ( "db0" , "db2" ) ; err == nil {
t . Fatalf ( "unexpected rename database success despite cq conflict" )
} else if err := data . DropContinuousQuery ( "db1" , "cq1" ) ; err != nil {
t . Fatal ( err )
} else if err := data . RenameDatabase ( "db0" , "db2" ) ; err == nil {
t . Fatalf ( "unexpected rename database success despite cq conflict" )
} else if err := data . DropContinuousQuery ( "db1" , "cq2" ) ; err != nil {
t . Fatal ( err )
} else if err := data . RenameDatabase ( "db0" , "db2" ) ; err != nil {
t . Fatal ( err )
}
}
2015-05-21 20:06:01 +00:00
// Ensure a retention policy can be created.
func TestData_CreateRetentionPolicy ( t * testing . T ) {
2015-06-11 06:01:03 +00:00
data := meta . Data { Nodes : [ ] meta . NodeInfo { { ID : 1 } , { ID : 2 } } }
2015-05-21 20:06:01 +00:00
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
}
// Create policy.
if err := data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo {
Name : "rp0" ,
ReplicaN : 2 ,
Duration : 4 * time . Hour ,
} ) ; err != nil {
t . Fatal ( err )
}
// Verify policy exists.
if ! reflect . DeepEqual ( data . Databases [ 0 ] . RetentionPolicies , [ ] meta . RetentionPolicyInfo {
{
Name : "rp0" ,
ReplicaN : 2 ,
Duration : 4 * time . Hour ,
ShardGroupDuration : 1 * time . Hour ,
} ,
} ) {
t . Fatalf ( "unexpected policies: %#v" , data . Databases [ 0 ] . RetentionPolicies )
}
}
// Ensure that creating a policy without a name returns an error.
func TestData_CreateRetentionPolicy_ErrNameRequired ( t * testing . T ) {
2015-06-11 06:01:03 +00:00
data := meta . Data { Nodes : [ ] meta . NodeInfo { { ID : 1 } } }
2015-05-21 20:06:01 +00:00
if err := data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "" } ) ; err != meta . ErrRetentionPolicyNameRequired {
t . Fatalf ( "unexpected error: %s" , err )
}
}
2015-08-12 19:42:25 +00:00
// Ensure that creating a policy with a replication factor less than 1 returns an error.
func TestData_CreateRetentionPolicy_ErrReplicationFactorTooLow ( t * testing . T ) {
data := meta . Data { Nodes : [ ] meta . NodeInfo { { ID : 1 } } }
if err := data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 0 } ) ; err != meta . ErrReplicationFactorTooLow {
2015-06-11 06:01:03 +00:00
t . Fatalf ( "unexpected error: %s" , err )
}
}
2015-05-21 20:06:01 +00:00
// Ensure that creating a retention policy on a non-existent database returns an error.
func TestData_CreateRetentionPolicy_ErrDatabaseNotFound ( t * testing . T ) {
2015-06-11 06:01:03 +00:00
data := meta . Data { Nodes : [ ] meta . NodeInfo { { ID : 1 } } }
if err := data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 1 } ) ; err != meta . ErrDatabaseNotFound {
2015-05-21 20:06:01 +00:00
t . Fatalf ( "unexpected error: %s" , err )
}
}
// Ensure that creating an already existing policy returns an error.
func TestData_CreateRetentionPolicy_ErrRetentionPolicyExists ( t * testing . T ) {
var data meta . Data
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
2015-08-12 19:42:25 +00:00
} else if err = data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 1 } ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
}
2015-08-12 19:42:25 +00:00
if err := data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 1 } ) ; err != meta . ErrRetentionPolicyExists {
2015-05-21 20:06:01 +00:00
t . Fatalf ( "unexpected error: %s" , err )
}
}
// Ensure that a retention policy can be updated.
func TestData_UpdateRetentionPolicy ( t * testing . T ) {
var data meta . Data
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
2015-08-12 19:42:25 +00:00
} else if err = data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 1 } ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
}
// Update the policy.
var rpu meta . RetentionPolicyUpdate
rpu . SetName ( "rp1" )
rpu . SetDuration ( 10 * time . Hour )
rpu . SetReplicaN ( 3 )
if err := data . UpdateRetentionPolicy ( "db0" , "rp0" , & rpu ) ; err != nil {
t . Fatal ( err )
}
// Verify the policy was changed.
if rpi , _ := data . RetentionPolicy ( "db0" , "rp1" ) ; ! reflect . DeepEqual ( rpi , & meta . RetentionPolicyInfo {
Name : "rp1" ,
Duration : 10 * time . Hour ,
2015-08-19 19:27:44 +00:00
ShardGroupDuration : 3600000000000 ,
2015-05-21 20:06:01 +00:00
ReplicaN : 3 ,
} ) {
t . Fatalf ( "unexpected policy: %#v" , rpi )
}
}
// Ensure a retention policy can be removed.
func TestData_DropRetentionPolicy ( t * testing . T ) {
var data meta . Data
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
2015-08-12 19:42:25 +00:00
} else if err = data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 1 } ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
}
if err := data . DropRetentionPolicy ( "db0" , "rp0" ) ; err != nil {
t . Fatal ( err )
} else if len ( data . Databases [ 0 ] . RetentionPolicies ) != 0 {
t . Fatalf ( "unexpected policies: %#v" , data . Databases [ 0 ] . RetentionPolicies )
}
}
// Ensure an error is returned when deleting a policy from a non-existent database.
func TestData_DropRetentionPolicy_ErrDatabaseNotFound ( t * testing . T ) {
var data meta . Data
if err := data . DropRetentionPolicy ( "db0" , "rp0" ) ; err != meta . ErrDatabaseNotFound {
t . Fatal ( err )
}
}
// Ensure an error is returned when deleting a non-existent policy.
func TestData_DropRetentionPolicy_ErrRetentionPolicyNotFound ( t * testing . T ) {
var data meta . Data
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
}
if err := data . DropRetentionPolicy ( "db0" , "rp0" ) ; err != meta . ErrRetentionPolicyNotFound {
t . Fatal ( err )
}
}
// Ensure that a retention policy can be retrieved.
func TestData_RetentionPolicy ( t * testing . T ) {
var data meta . Data
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
2015-08-12 19:42:25 +00:00
} else if err = data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 1 } ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
2015-08-12 19:42:25 +00:00
} else if err = data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp1" , ReplicaN : 1 } ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
}
if rpi , err := data . RetentionPolicy ( "db0" , "rp0" ) ; err != nil {
t . Fatal ( err )
} else if ! reflect . DeepEqual ( rpi , & meta . RetentionPolicyInfo {
Name : "rp0" ,
ShardGroupDuration : 604800000000000 ,
2015-08-12 19:42:25 +00:00
ReplicaN : 1 ,
2015-05-21 20:06:01 +00:00
} ) {
t . Fatalf ( "unexpected value: %#v" , rpi )
}
}
2015-06-28 06:54:34 +00:00
// Ensure that retrieving a policy from a non-existent database returns an error.
2015-05-21 20:06:01 +00:00
func TestData_RetentionPolicy_ErrDatabaseNotFound ( t * testing . T ) {
var data meta . Data
if _ , err := data . RetentionPolicy ( "db0" , "rp0" ) ; err != meta . ErrDatabaseNotFound {
t . Fatal ( err )
}
}
// Ensure that a default retention policy can be set.
func TestData_SetDefaultRetentionPolicy ( t * testing . T ) {
var data meta . Data
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
2015-08-12 19:42:25 +00:00
} else if err = data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 1 } ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
}
// Verify there is no default policy on the database initially.
if name := data . Database ( "db0" ) . DefaultRetentionPolicy ; name != "" {
t . Fatalf ( "unexpected initial default retention policy: %s" , name )
}
// Set the default policy.
if err := data . SetDefaultRetentionPolicy ( "db0" , "rp0" ) ; err != nil {
t . Fatal ( err )
}
// Verify the default policy is now set.
if name := data . Database ( "db0" ) . DefaultRetentionPolicy ; name != "rp0" {
t . Fatalf ( "unexpected default retention policy: %s" , name )
}
}
// Ensure that a shard group can be created on a database for a given timestamp.
func TestData_CreateShardGroup ( t * testing . T ) {
var data meta . Data
if err := data . CreateNode ( "node0" ) ; err != nil {
t . Fatal ( err )
} else if err = data . CreateNode ( "node1" ) ; err != nil {
t . Fatal ( err )
} else if err = data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
2015-06-11 06:01:03 +00:00
} else if err = data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 2 , Duration : 1 * time . Hour } ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
}
// Create shard group.
if err := data . CreateShardGroup ( "db0" , "rp0" , time . Date ( 2000 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) ) ; err != nil {
t . Fatal ( err )
}
// Verify the shard group was created.
if sgi , _ := data . ShardGroupByTimestamp ( "db0" , "rp0" , time . Date ( 2000 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) ) ; ! reflect . DeepEqual ( sgi , & meta . ShardGroupInfo {
ID : 1 ,
StartTime : time . Date ( 2000 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
EndTime : time . Date ( 2000 , time . January , 1 , 1 , 0 , 0 , 0 , time . UTC ) ,
Shards : [ ] meta . ShardInfo {
2015-08-31 22:03:44 +00:00
{
ID : 1 ,
Owners : [ ] meta . ShardOwner {
{ NodeID : 1 } ,
{ NodeID : 2 } ,
} ,
} ,
2015-05-21 20:06:01 +00:00
} ,
} ) {
t . Fatalf ( "unexpected shard group: %#v" , sgi )
2015-06-29 16:30:51 +00:00
} else if ! sgi . Shards [ 0 ] . OwnedBy ( 1 ) || ! sgi . Shards [ 0 ] . OwnedBy ( 2 ) || sgi . Shards [ 0 ] . OwnedBy ( 3 ) {
// Verify shard is correctly owned-by the node.
t . Fatalf ( "new shard is not owned by correct node" )
2015-05-21 20:06:01 +00:00
}
}
2015-06-05 19:28:20 +00:00
// Ensure that a shard group is correctly detected as expired.
func TestData_ShardGroupExpiredDeleted ( t * testing . T ) {
var data meta . Data
if err := data . CreateNode ( "node0" ) ; err != nil {
t . Fatal ( err )
} else if err = data . CreateNode ( "node1" ) ; err != nil {
t . Fatal ( err )
} else if err = data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
2015-06-11 06:01:03 +00:00
} else if err = data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 2 , Duration : 1 * time . Hour } ) ; err != nil {
2015-06-05 19:28:20 +00:00
t . Fatal ( err )
}
// Create shard groups.
if err := data . CreateShardGroup ( "db0" , "rp0" , time . Date ( 2000 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) ) ; err != nil {
t . Fatal ( err )
}
if err := data . CreateShardGroup ( "db0" , "rp0" , time . Date ( 2001 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) ) ; err != nil {
t . Fatal ( err )
}
// Check expiration.
rp , _ := data . RetentionPolicy ( "db0" , "rp0" )
groups := rp . ExpiredShardGroups ( time . Date ( 2001 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) )
if len ( groups ) != 1 {
t . Fatalf ( "wrong number of expired shard groups returned, got %d, exp 1" , len ( groups ) )
}
if groups [ 0 ] . StartTime != time . Date ( 2000 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) {
t . Fatal ( "wrong shard group marked as expired" )
}
// Check deletion.
if err := data . DeleteShardGroup ( "db0" , "rp0" , groups [ 0 ] . ID ) ; err != nil {
t . Fatal ( err )
}
groups = rp . DeletedShardGroups ( )
if len ( groups ) != 1 {
t . Fatalf ( "wrong number of deleted shard groups returned, got %d, exp 1" , len ( groups ) )
}
if groups [ 0 ] . StartTime != time . Date ( 2000 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) {
t . Fatal ( "wrong shard group marked as expired" )
}
}
2015-05-28 22:02:12 +00:00
// Test shard group selection.
func TestShardGroup_Overlaps ( t * testing . T ) {
// Make a shard group 1 hour in duration
startTime , _ := time . Parse ( time . RFC3339 , "2000-01-01T00:00:00Z" )
endTime := startTime . Add ( time . Hour )
g := & meta . ShardGroupInfo { StartTime : startTime , EndTime : endTime }
if ! g . Overlaps ( g . StartTime . Add ( - time . Minute ) , g . EndTime ) {
t . Fatal ( "shard group not selected when min before start time" )
}
if ! g . Overlaps ( g . StartTime . Add ( - time . Minute ) , g . StartTime ) {
t . Fatal ( "shard group not selected when min before start time and max equals start time" )
}
if ! g . Overlaps ( g . StartTime , g . EndTime . Add ( time . Minute ) ) {
t . Fatal ( "shard group not selected when max after after end time" )
}
if ! g . Overlaps ( g . StartTime . Add ( - time . Minute ) , g . EndTime . Add ( time . Minute ) ) {
t . Fatal ( "shard group not selected when min before start time and when max after end time" )
}
if ! g . Overlaps ( g . StartTime . Add ( time . Minute ) , g . EndTime . Add ( - time . Minute ) ) {
t . Fatal ( "shard group not selected when min after start time and when max before end time" )
}
if ! g . Overlaps ( g . StartTime , g . EndTime ) {
t . Fatal ( "shard group not selected when min at start time and when max at end time" )
}
if ! g . Overlaps ( g . StartTime , g . StartTime ) {
t . Fatal ( "shard group not selected when min and max set to start time" )
}
if ! g . Overlaps ( g . StartTime . Add ( 1 * time . Minute ) , g . EndTime . Add ( 24 * time . Hour ) ) {
t . Fatal ( "shard group selected when both min in range" )
}
if g . Overlaps ( g . EndTime , g . EndTime ) {
t . Fatal ( "shard group selected when min and max set to end time" )
}
if g . Overlaps ( g . StartTime . Add ( - 10 * time . Hour ) , g . EndTime . Add ( - 9 * time . Hour ) ) {
t . Fatal ( "shard group selected when both min and max before shard times" )
}
if g . Overlaps ( g . StartTime . Add ( 24 * time . Hour ) , g . EndTime . Add ( 25 * time . Hour ) ) {
t . Fatal ( "shard group selected when both min and max after shard times" )
}
}
2015-05-21 20:06:01 +00:00
// Ensure a shard group can be removed by ID.
func TestData_DeleteShardGroup ( t * testing . T ) {
var data meta . Data
if err := data . CreateNode ( "node0" ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
2015-06-11 06:01:03 +00:00
} else if err = data . CreateRetentionPolicy ( "db0" , & meta . RetentionPolicyInfo { Name : "rp0" , ReplicaN : 1 } ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
} else if err := data . CreateShardGroup ( "db0" , "rp0" , time . Date ( 2000 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) ) ; err != nil {
t . Fatal ( err )
}
if err := data . DeleteShardGroup ( "db0" , "rp0" , 1 ) ; err != nil {
t . Fatal ( err )
2015-06-04 22:50:33 +00:00
}
if sg := data . Databases [ 0 ] . RetentionPolicies [ 0 ] . ShardGroups [ 0 ] ; ! sg . Deleted ( ) {
t . Fatalf ( "shard group not correctly flagged as deleted" )
2015-05-21 20:06:01 +00:00
}
}
// Ensure a continuous query can be created.
func TestData_CreateContinuousQuery ( t * testing . T ) {
var data meta . Data
2015-05-28 04:06:09 +00:00
if err := data . CreateDatabase ( "db0" ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateContinuousQuery ( "db0" , "cq0" , "SELECT count() FROM foo" ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
2015-05-28 04:06:09 +00:00
} else if ! reflect . DeepEqual ( data . Databases [ 0 ] . ContinuousQueries , [ ] meta . ContinuousQueryInfo {
{ Name : "cq0" , Query : "SELECT count() FROM foo" } ,
} ) {
t . Fatalf ( "unexpected queries: %#v" , data . Databases [ 0 ] . ContinuousQueries )
2015-05-21 20:06:01 +00:00
}
}
// Ensure a continuous query can be removed.
func TestData_DropContinuousQuery ( t * testing . T ) {
var data meta . Data
2015-05-28 04:06:09 +00:00
if err := data . CreateDatabase ( "db0" ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
2015-05-28 04:06:09 +00:00
} else if err := data . CreateContinuousQuery ( "db0" , "cq0" , "SELECT count() FROM foo" ) ; err != nil {
t . Fatal ( err )
} else if err = data . CreateContinuousQuery ( "db0" , "cq1" , "SELECT count() FROM bar" ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
}
2015-05-28 04:06:09 +00:00
if err := data . DropContinuousQuery ( "db0" , "cq0" ) ; err != nil {
2015-05-21 20:06:01 +00:00
t . Fatal ( err )
2015-05-28 04:06:09 +00:00
} else if ! reflect . DeepEqual ( data . Databases [ 0 ] . ContinuousQueries , [ ] meta . ContinuousQueryInfo {
{ Name : "cq1" , Query : "SELECT count() FROM bar" } ,
2015-05-21 20:06:01 +00:00
} ) {
2015-05-28 04:06:09 +00:00
t . Fatalf ( "unexpected queries: %#v" , data . Databases [ 0 ] . ContinuousQueries )
2015-05-21 20:06:01 +00:00
}
}
// Ensure a user can be created.
func TestData_CreateUser ( t * testing . T ) {
var data meta . Data
if err := data . CreateUser ( "susy" , "ABC123" , true ) ; err != nil {
t . Fatal ( err )
} else if ! reflect . DeepEqual ( data . Users , [ ] meta . UserInfo {
{ Name : "susy" , Hash : "ABC123" , Admin : true } ,
} ) {
t . Fatalf ( "unexpected users: %#v" , data . Users )
}
}
// Ensure that creating a user with no username returns an error.
func TestData_CreateUser_ErrUsernameRequired ( t * testing . T ) {
var data meta . Data
if err := data . CreateUser ( "" , "" , false ) ; err != meta . ErrUsernameRequired {
t . Fatal ( err )
}
}
// Ensure that creating the same user twice returns an error.
func TestData_CreateUser_ErrUserExists ( t * testing . T ) {
var data meta . Data
if err := data . CreateUser ( "susy" , "" , false ) ; err != nil {
t . Fatal ( err )
}
if err := data . CreateUser ( "susy" , "" , false ) ; err != meta . ErrUserExists {
t . Fatal ( err )
}
}
// Ensure a user can be removed.
func TestData_DropUser ( t * testing . T ) {
var data meta . Data
if err := data . CreateUser ( "susy" , "" , false ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateUser ( "bob" , "" , false ) ; err != nil {
t . Fatal ( err )
}
if err := data . DropUser ( "bob" ) ; err != nil {
t . Fatal ( err )
} else if ! reflect . DeepEqual ( data . Users , [ ] meta . UserInfo {
{ Name : "susy" } ,
} ) {
t . Fatalf ( "unexpected users: %#v" , data . Users )
}
}
// Ensure that removing a non-existent user returns an error.
func TestData_DropUser_ErrUserNotFound ( t * testing . T ) {
var data meta . Data
if err := data . DropUser ( "bob" ) ; err != meta . ErrUserNotFound {
t . Fatal ( err )
}
}
// Ensure a user can be updated.
func TestData_UpdateUser ( t * testing . T ) {
var data meta . Data
if err := data . CreateUser ( "susy" , "" , false ) ; err != nil {
t . Fatal ( err )
} else if err := data . CreateUser ( "bob" , "" , false ) ; err != nil {
t . Fatal ( err )
}
// Update password hash.
if err := data . UpdateUser ( "bob" , "XXX" ) ; err != nil {
t . Fatal ( err )
} else if ! reflect . DeepEqual ( data . User ( "bob" ) , & meta . UserInfo { Name : "bob" , Hash : "XXX" } ) {
t . Fatalf ( "unexpected user: %#v" , data . User ( "bob" ) )
}
}
// Ensure that updating a non-existent user returns an error.
func TestData_UpdateUser_ErrUserNotFound ( t * testing . T ) {
var data meta . Data
if err := data . UpdateUser ( "bob" , "ZZZ" ) ; err != meta . ErrUserNotFound {
t . Fatal ( err )
}
}
2015-05-20 20:57:04 +00:00
// Ensure the data can be deeply copied.
func TestData_Clone ( t * testing . T ) {
data := meta . Data {
2015-06-05 20:40:18 +00:00
Term : 10 ,
Index : 20 ,
2015-05-20 20:57:04 +00:00
Nodes : [ ] meta . NodeInfo {
{ ID : 1 , Host : "host0" } ,
{ ID : 2 , Host : "host1" } ,
} ,
Databases : [ ] meta . DatabaseInfo {
{
Name : "db0" ,
DefaultRetentionPolicy : "default" ,
2015-05-21 20:06:01 +00:00
RetentionPolicies : [ ] meta . RetentionPolicyInfo {
2015-05-20 20:57:04 +00:00
{
Name : "rp0" ,
ReplicaN : 3 ,
Duration : 10 * time . Second ,
ShardGroupDuration : 3 * time . Millisecond ,
ShardGroups : [ ] meta . ShardGroupInfo {
{
ID : 100 ,
StartTime : time . Date ( 2000 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
EndTime : time . Date ( 2000 , time . February , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
Shards : [ ] meta . ShardInfo {
{
2015-08-31 22:03:44 +00:00
ID : 200 ,
Owners : [ ] meta . ShardOwner {
{ NodeID : 1 } ,
{ NodeID : 3 } ,
{ NodeID : 4 } ,
} ,
2015-05-20 20:57:04 +00:00
} ,
} ,
} ,
} ,
} ,
} ,
2015-05-28 04:06:09 +00:00
ContinuousQueries : [ ] meta . ContinuousQueryInfo {
{ Query : "SELECT count() FROM foo" } ,
} ,
2015-05-20 20:57:04 +00:00
} ,
} ,
Users : [ ] meta . UserInfo {
{
Name : "susy" ,
Hash : "ABC123" ,
Admin : true ,
Privileges : map [ string ] influxql . Privilege { "db0" : influxql . AllPrivileges } ,
} ,
} ,
}
// Copy the root structure.
other := data . Clone ( )
2015-06-05 20:40:18 +00:00
if ! reflect . DeepEqual ( data . Nodes , other . Nodes ) {
2015-05-20 20:57:04 +00:00
t . Fatalf ( "unexpected cloned nodes: %#v" , other . Nodes )
} else if ! reflect . DeepEqual ( data . Databases , other . Databases ) {
t . Fatalf ( "unexpected cloned databases: %#v" , other . Databases )
} else if ! reflect . DeepEqual ( data . Users , other . Users ) {
t . Fatalf ( "unexpected cloned users: %#v" , other . Users )
}
// Ensure that changing data in the clone does not affect the original.
2015-08-31 22:03:44 +00:00
other . Databases [ 0 ] . RetentionPolicies [ 0 ] . ShardGroups [ 0 ] . Shards [ 0 ] . Owners [ 1 ] . NodeID = 9
if v := data . Databases [ 0 ] . RetentionPolicies [ 0 ] . ShardGroups [ 0 ] . Shards [ 0 ] . Owners [ 1 ] . NodeID ; v != 3 {
2015-05-20 20:57:04 +00:00
t . Fatalf ( "editing clone changed original: %v" , v )
}
}
2015-06-08 19:07:05 +00:00
// Ensure the data can be marshaled and unmarshaled.
func TestData_MarshalBinary ( t * testing . T ) {
data := meta . Data {
Term : 10 ,
Index : 20 ,
Nodes : [ ] meta . NodeInfo {
{ ID : 1 , Host : "host0" } ,
{ ID : 2 , Host : "host1" } ,
} ,
Databases : [ ] meta . DatabaseInfo {
{
Name : "db0" ,
DefaultRetentionPolicy : "default" ,
RetentionPolicies : [ ] meta . RetentionPolicyInfo {
{
Name : "rp0" ,
ReplicaN : 3 ,
Duration : 10 * time . Second ,
ShardGroupDuration : 3 * time . Millisecond ,
ShardGroups : [ ] meta . ShardGroupInfo {
{
ID : 100 ,
StartTime : time . Date ( 2000 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
EndTime : time . Date ( 2000 , time . February , 1 , 0 , 0 , 0 , 0 , time . UTC ) ,
Shards : [ ] meta . ShardInfo {
{
2015-08-31 22:03:44 +00:00
ID : 200 ,
Owners : [ ] meta . ShardOwner {
{ NodeID : 1 } ,
{ NodeID : 3 } ,
{ NodeID : 4 } ,
} ,
2015-06-08 19:07:05 +00:00
} ,
} ,
} ,
} ,
} ,
} ,
ContinuousQueries : [ ] meta . ContinuousQueryInfo {
{ Query : "SELECT count() FROM foo" } ,
} ,
} ,
} ,
Users : [ ] meta . UserInfo {
{
Name : "susy" ,
Hash : "ABC123" ,
Admin : true ,
Privileges : map [ string ] influxql . Privilege { "db0" : influxql . AllPrivileges } ,
} ,
} ,
}
// Marshal the data struture.
buf , err := data . MarshalBinary ( )
2015-05-20 20:57:04 +00:00
if err != nil {
t . Fatal ( err )
}
2015-06-08 19:07:05 +00:00
// Unmarshal into new data.
var other meta . Data
2015-05-20 20:57:04 +00:00
if err := other . UnmarshalBinary ( buf ) ; err != nil {
t . Fatal ( err )
2015-06-08 19:07:05 +00:00
}
if ! reflect . DeepEqual ( data . Nodes , other . Nodes ) {
t . Fatalf ( "unexpected nodes: %#v" , other . Nodes )
} else if ! reflect . DeepEqual ( data . Databases , other . Databases ) {
spew . Dump ( data . Databases )
spew . Dump ( other . Databases )
t . Fatalf ( "unexpected databases: %#v" , other . Databases )
} else if ! reflect . DeepEqual ( data . Users , other . Users ) {
t . Fatalf ( "unexpected users: %#v" , other . Users )
2015-05-20 20:57:04 +00:00
}
}
2015-08-31 22:03:44 +00:00
// Ensure shards with deprecated "OwnerIDs" can be decoded.
func TestShardInfo_UnmarshalBinary_OwnerIDs ( t * testing . T ) {
// Encode deprecated form to bytes.
buf , err := proto . Marshal ( & internal . ShardInfo {
ID : proto . Uint64 ( 1 ) ,
OwnerIDs : [ ] uint64 { 10 , 20 , 30 } ,
} )
if err != nil {
t . Fatal ( err )
}
// Decode deprecated form.
var si meta . ShardInfo
if err := si . UnmarshalBinary ( buf ) ; err != nil {
t . Fatal ( err )
}
// Verify data is migrated correctly.
if ! reflect . DeepEqual ( si , meta . ShardInfo {
ID : 1 ,
Owners : [ ] meta . ShardOwner {
{ NodeID : 10 } ,
{ NodeID : 20 } ,
{ NodeID : 30 } ,
} ,
} ) {
t . Fatalf ( "unexpected shard info: %s" , spew . Sdump ( si ) )
}
}