// Ensure a SHOW GRANTS FOR statement can be executed.
func TestStatementExecutor_ExecuteStatement_ShowGrantsFor(t *testing.T) {
	t.Skip("Intermittent test failure: issue 3028")
	e := NewStatementExecutor()
	e.Store.UserPrivilegesFn = func(username string) (map[string]influxql.Privilege, error) {
		if username != "dejan" {
			t.Fatalf("unexpected username: %s", username)
		}
		return map[string]influxql.Privilege{
			"dejan": influxql.ReadPrivilege,
			"golja": influxql.WritePrivilege,
		}, nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW GRANTS FOR dejan`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if !reflect.DeepEqual(res.Series, models.Rows{
		{
			Columns: []string{"database", "privilege"},
			Values: [][]interface{}{
				{"dejan", "READ"},
				{"golja", "WRITE"},
			},
		},
	}) {
		t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series))
	}
}
// Ensure a SHOW SERVERS statement can be executed.
func TestStatementExecutor_ExecuteStatement_ShowServers(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.NodesFn = func() ([]meta.NodeInfo, error) {
		return []meta.NodeInfo{
			{ID: 1, Host: "node0"},
			{ID: 2, Host: "node1"},
		}, nil
	}
	e.Store.PeersFn = func() ([]string, error) {
		return []string{"node0"}, nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW SERVERS`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if !reflect.DeepEqual(res.Series, models.Rows{
		{
			Columns: []string{"id", "cluster_addr", "raft"},
			Values: [][]interface{}{
				{uint64(1), "node0", true},
				{uint64(2), "node1", false},
			},
		},
	}) {
		t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series))
	}
}
// Ensure a CREATE RETENTION POLICY statement can be executed.
func TestStatementExecutor_ExecuteStatement_CreateRetentionPolicy(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.CreateRetentionPolicyFn = func(database string, rpi *meta.RetentionPolicyInfo) (*meta.RetentionPolicyInfo, error) {
		if database != "foo" {
			t.Fatalf("unexpected database: %s", database)
		} else if rpi.Name != "rp0" {
			t.Fatalf("unexpected name: %s", rpi.Name)
		} else if rpi.Duration != 2*time.Hour {
			t.Fatalf("unexpected duration: %v", rpi.Duration)
		} else if rpi.ReplicaN != 3 {
			t.Fatalf("unexpected replication factor: %v", rpi.ReplicaN)
		}
		return nil, nil
	}
	e.Store.SetDefaultRetentionPolicyFn = func(database, name string) error {
		if database != "foo" {
			t.Fatalf("unexpected database: %s", database)
		} else if name != "rp0" {
			t.Fatalf("unexpected name: %s", name)
		}
		return nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`CREATE RETENTION POLICY rp0 ON foo DURATION 2h REPLICATION 3 DEFAULT`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if res.Series != nil {
		t.Fatalf("unexpected rows: %#v", res.Series)
	}
}
// Ensure a CREATE USER statement returns errors from the store.
func TestStatementExecutor_ExecuteStatement_CreateUser_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.CreateUserFn = func(name, password string, admin bool) (*meta.UserInfo, error) {
		return nil, errors.New("marker")
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`CREATE USER susy WITH PASSWORD 'pass'`)); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a SHOW RETENTION POLICIES statement can return an error from the store.
func TestStatementExecutor_ExecuteStatement_ShowRetentionPolicies_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DatabaseFn = func(name string) (*meta.DatabaseInfo, error) {
		return nil, errors.New("marker")
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW RETENTION POLICIES ON db0`)); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a CREATE RETENTION POLICY statement returns errors from the store.
func TestStatementExecutor_ExecuteStatement_CreateRetentionPolicy_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.CreateRetentionPolicyFn = func(database string, rpi *meta.RetentionPolicyInfo) (*meta.RetentionPolicyInfo, error) {
		return nil, errors.New("marker")
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`CREATE RETENTION POLICY rp0 ON foo DURATION 2h REPLICATION 1`)); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a SHOW RETENTION POLICIES statement can return an error if the database doesn't exist.
func TestStatementExecutor_ExecuteStatement_ShowRetentionPolicies_ErrDatabaseNotFound(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DatabaseFn = func(name string) (*meta.DatabaseInfo, error) {
		return nil, nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW RETENTION POLICIES ON db0`)); res.Err != meta.ErrDatabaseNotFound {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a REVOKE statement for admin privilege returns errors from the store.
func TestStatementExecutor_ExecuteStatement_RevokeAdmin_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.SetAdminPrivilegeFn = func(username string, admin bool) error {
		return errors.New("marker")
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`REVOKE ALL PRIVILEGES FROM susy`)); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a DROP USER statement returns errors from the store.
func TestStatementExecutor_ExecuteStatement_DropUser_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DropUserFn = func(name string) error {
		return errors.New("marker")
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`DROP USER susy`)); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a GRANT statement returns errors from the store.
func TestStatementExecutor_ExecuteStatement_Grant_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.SetPrivilegeFn = func(username, database string, p influxql.Privilege) error {
		return errors.New("marker")
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`GRANT READ ON foo TO susy`)); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a SET PASSWORD statement returns errors from the store.
func TestStatementExecutor_ExecuteStatement_SetPassword_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.UpdateUserFn = func(name, password string) error {
		return errors.New("marker")
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`SET PASSWORD FOR susy = 'pass'`)); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a SHOW DATABASES statement returns errors from the store.
func TestStatementExecutor_ExecuteStatement_ShowDatabases_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DatabasesFn = func() ([]meta.DatabaseInfo, error) {
		return nil, errors.New("marker")
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW DATABASES`)); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a CREATE CONTINUOUS QUERY statement can return an error from the store.
func TestStatementExecutor_ExecuteStatement_CreateContinuousQuery_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.CreateContinuousQueryFn = func(database, name, query string) error {
		return errors.New("marker")
	}

	stmt := influxql.MustParseStatement(`CREATE CONTINUOUS QUERY cq0 ON db0 BEGIN SELECT count(field1) INTO db1 FROM db0 GROUP BY time(1h) END`)
	if res := e.ExecuteStatement(stmt); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a DROP CONTINUOUS QUERY statement can return an error from the store.
func TestStatementExecutor_ExecuteStatement_DropContinuousQuery_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DropContinuousQueryFn = func(database, name string) error {
		return errors.New("marker")
	}

	stmt := influxql.MustParseStatement(`DROP CONTINUOUS QUERY cq0 ON db0`)
	if res := e.ExecuteStatement(stmt); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a SHOW CONTINUOUS QUERIES statement can return an error from the store.
func TestStatementExecutor_ExecuteStatement_ShowContinuousQueries_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DatabasesFn = func() ([]meta.DatabaseInfo, error) {
		return nil, errors.New("marker")
	}

	stmt := influxql.MustParseStatement(`SHOW CONTINUOUS QUERIES`)
	if res := e.ExecuteStatement(stmt); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatal(res.Err)
	}
}
// Ensure a DROP RETENTION POLICY statement returns errors from the store.
func TestStatementExecutor_ExecuteStatement_DropRetentionPolicy_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DropRetentionPolicyFn = func(database, name string) error {
		return errors.New("marker")
	}

	stmt := influxql.MustParseStatement(`DROP RETENTION POLICY rp0 ON foo`)
	if res := e.ExecuteStatement(stmt); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a ALTER RETENTION POLICY statement returns errors from the store.
func TestStatementExecutor_ExecuteStatement_AlterRetentionPolicy_Err(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.UpdateRetentionPolicyFn = func(database, name string, rpu *meta.RetentionPolicyUpdate) error {
		return errors.New("marker")
	}

	stmt := influxql.MustParseStatement(`ALTER RETENTION POLICY rp0 ON foo DURATION 1m REPLICATION 4 DEFAULT`)
	if res := e.ExecuteStatement(stmt); res.Err == nil || res.Err.Error() != "marker" {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure an ALTER RETENTION POLICY statement can execute.
func TestStatementExecutor_ExecuteStatement_AlterRetentionPolicy(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.UpdateRetentionPolicyFn = func(database, name string, rpu *meta.RetentionPolicyUpdate) error {
		if database != "foo" {
			t.Fatalf("unexpected database: %s", database)
		} else if name != "rp0" {
			t.Fatalf("unexpected name: %s", name)
		} else if rpu.Duration != nil && *rpu.Duration != 7*24*time.Hour {
			t.Fatalf("unexpected duration: %v", *rpu.Duration)
		} else if rpu.ReplicaN != nil && *rpu.ReplicaN != 2 {
			t.Fatalf("unexpected replication factor: %v", *rpu.ReplicaN)
		}
		return nil
	}
	e.Store.SetDefaultRetentionPolicyFn = func(database, name string) error {
		if database != "foo" {
			t.Fatalf("unexpected database: %s", database)
		} else if name != "rp0" {
			t.Fatalf("unexpected name: %s", name)
		}
		return nil
	}

	stmt := influxql.MustParseStatement(`ALTER RETENTION POLICY rp0 ON foo DURATION 7d REPLICATION 2 DEFAULT`)
	if res := e.ExecuteStatement(stmt); res.Err != nil {
		t.Fatalf("unexpected error: %s", res.Err)
	}

	stmt = influxql.MustParseStatement(`ALTER RETENTION POLICY rp0 ON foo DURATION 7d`)
	if res := e.ExecuteStatement(stmt); res.Err != nil {
		t.Fatalf("unexpected error: %s", res.Err)
	}

	stmt = influxql.MustParseStatement(`ALTER RETENTION POLICY rp0 ON foo REPLICATION 2`)
	if res := e.ExecuteStatement(stmt); res.Err != nil {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a SHOW SHARDS statement can be executed.
func TestStatementExecutor_ExecuteStatement_ShowShards(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DatabasesFn = func() ([]meta.DatabaseInfo, error) {
		return []meta.DatabaseInfo{
			{
				Name: "foo",
				RetentionPolicies: []meta.RetentionPolicyInfo{
					{
						Duration: time.Second,
						ShardGroups: []meta.ShardGroupInfo{
							{
								StartTime: time.Unix(0, 0),
								EndTime:   time.Unix(1, 0),
								Shards: []meta.ShardInfo{
									{
										ID: 1,
										Owners: []meta.ShardOwner{
											{NodeID: 1},
											{NodeID: 2},
											{NodeID: 3},
										},
									},
									{
										ID: 2,
									},
								},
							},
						},
					},
				},
			},
		}, nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`SHOW SHARDS`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if !reflect.DeepEqual(res.Series, models.Rows{
		{
			Name:    "foo",
			Columns: []string{"id", "start_time", "end_time", "expiry_time", "owners"},
			Values: [][]interface{}{
				{uint64(1), "1970-01-01T00:00:00Z", "1970-01-01T00:00:01Z", "1970-01-01T00:00:02Z", "1,2,3"},
				{uint64(2), "1970-01-01T00:00:00Z", "1970-01-01T00:00:01Z", "1970-01-01T00:00:02Z", ""},
			},
		},
	}) {
		t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series))
	}
}
// Ensure a DROP DATABASE statement can be executed.
func TestStatementExecutor_ExecuteStatement_DropDatabase(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DropDatabaseFn = func(name string) error {
		if name != "foo" {
			t.Fatalf("unexpected name: %s", name)
		}
		return nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`DROP DATABASE foo`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if res.Series != nil {
		t.Fatalf("unexpected rows: %#v", res.Series)
	}
}
// Ensure a CREATE DATABASE statement can be executed.
func TestStatementExecutor_ExecuteStatement_CreateDatabase(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.CreateDatabaseFn = func(name string) (*meta.DatabaseInfo, error) {
		if name != "foo" {
			t.Fatalf("unexpected name: %s", name)
		}
		return &meta.DatabaseInfo{Name: name}, nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`CREATE DATABASE foo`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if res.Series != nil {
		t.Fatalf("unexpected rows: %#v", res.Series)
	}
}
// Ensure a DROP RETENTION POLICY statement can execute.
func TestStatementExecutor_ExecuteStatement_DropRetentionPolicy(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DropRetentionPolicyFn = func(database, name string) error {
		if database != "foo" {
			t.Fatalf("unexpected database: %s", database)
		} else if name != "rp0" {
			t.Fatalf("unexpected name: %s", name)
		}
		return nil
	}

	stmt := influxql.MustParseStatement(`DROP RETENTION POLICY rp0 ON foo`)
	if res := e.ExecuteStatement(stmt); res.Err != nil {
		t.Fatalf("unexpected error: %s", res.Err)
	}
}
// Ensure a SET PASSWORD statement can be executed.
func TestStatementExecutor_ExecuteStatement_SetPassword(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.UpdateUserFn = func(name, password string) error {
		if name != "susy" {
			t.Fatalf("unexpected name: %s", name)
		} else if password != "pass" {
			t.Fatalf("unexpected password: %s", password)
		}
		return nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`SET PASSWORD FOR susy = 'pass' WITH ALL PRIVILEGES`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if res.Series != nil {
		t.Fatalf("unexpected rows: %#v", res.Series)
	}
}
// Ensure a REVOKE statement for admin privilege can be executed.
func TestStatementExecutor_ExecuteStatement_RevokeAdmin(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.SetAdminPrivilegeFn = func(username string, admin bool) error {
		if username != "susy" {
			t.Fatalf("unexpected username: %s", username)
		} else if admin != false {
			t.Fatalf("unexpected admin privilege: %t", admin)
		}
		return nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`REVOKE ALL PRIVILEGES FROM susy`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if res.Series != nil {
		t.Fatalf("unexpected rows: %#v", res.Series)
	}
}
// Ensure a DROP CONTINUOUS QUERY statement can be executed.
func TestStatementExecutor_ExecuteStatement_DropContinuousQuery(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DropContinuousQueryFn = func(database, name string) error {
		if database != "db0" {
			t.Fatalf("unexpected database: %s", database)
		} else if name != "cq0" {
			t.Fatalf("unexpected name: %s", name)
		}
		return nil
	}

	stmt := influxql.MustParseStatement(`DROP CONTINUOUS QUERY cq0 ON db0`)
	if res := e.ExecuteStatement(stmt); res.Err != nil {
		t.Fatal(res.Err)
	} else if res.Series != nil {
		t.Fatalf("unexpected rows: %#v", res.Series)
	}
}
// Ensure a CREATE USER statement can be executed.
func TestStatementExecutor_ExecuteStatement_CreateUser(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.CreateUserFn = func(name, password string, admin bool) (*meta.UserInfo, error) {
		if name != "susy" {
			t.Fatalf("unexpected name: %s", name)
		} else if password != "pass" {
			t.Fatalf("unexpected password: %s", password)
		} else if admin != true {
			t.Fatalf("unexpected admin: %v", admin)
		}
		return &meta.UserInfo{Name: name, Admin: admin}, nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`CREATE USER susy WITH PASSWORD 'pass' WITH ALL PRIVILEGES`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if res.Series != nil {
		t.Fatalf("unexpected rows: %#v", res.Series)
	}
}
// Ensure a GRANT statement can be executed.
func TestStatementExecutor_ExecuteStatement_Grant(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.SetPrivilegeFn = func(username, database string, p influxql.Privilege) error {
		if username != "susy" {
			t.Fatalf("unexpected username: %s", username)
		} else if database != "foo" {
			t.Fatalf("unexpected database: %s", database)
		} else if p != influxql.WritePrivilege {
			t.Fatalf("unexpected privilege: %s", p)
		}
		return nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`GRANT WRITE ON foo TO susy`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if res.Series != nil {
		t.Fatalf("unexpected rows: %#v", res.Series)
	}
}
// Ensure a SHOW CONTINUOUS QUERIES statement can be executed.
func TestStatementExecutor_ExecuteStatement_ShowContinuousQueries(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.DatabasesFn = func() ([]meta.DatabaseInfo, error) {
		return []meta.DatabaseInfo{
			{
				Name: "db0",
				ContinuousQueries: []meta.ContinuousQueryInfo{
					{Name: "cq0", Query: "SELECT count(field1) INTO db1 FROM db0"},
					{Name: "cq1", Query: "SELECT count(field1) INTO db2 FROM db0"},
				},
			},
			{
				Name: "db1",
				ContinuousQueries: []meta.ContinuousQueryInfo{
					{Name: "cq2", Query: "SELECT count(field1) INTO db3 FROM db1"},
				},
			},
		}, nil
	}

	stmt := influxql.MustParseStatement(`SHOW CONTINUOUS QUERIES`)
	if res := e.ExecuteStatement(stmt); res.Err != nil {
		t.Fatal(res.Err)
	} else if !reflect.DeepEqual(res.Series, models.Rows{
		{
			Name:    "db0",
			Columns: []string{"name", "query"},
			Values: [][]interface{}{
				{"cq0", "SELECT count(field1) INTO db1 FROM db0"},
				{"cq1", "SELECT count(field1) INTO db2 FROM db0"},
			},
		},
		{
			Name:    "db1",
			Columns: []string{"name", "query"},
			Values: [][]interface{}{
				{"cq2", "SELECT count(field1) INTO db3 FROM db1"},
			},
		},
	}) {
		t.Fatalf("unexpected rows: %s", spew.Sdump(res.Series))
	}
}
// Ensure a REVOKE statement can be executed.
func TestStatementExecutor_ExecuteStatement_Revoke(t *testing.T) {
	e := NewStatementExecutor()
	e.Store.SetPrivilegeFn = func(username, database string, p influxql.Privilege) error {
		if username != "susy" {
			t.Fatalf("unexpected username: %s", username)
		} else if database != "foo" {
			t.Fatalf("unexpected database: %s", database)
		} else if p != influxql.NoPrivileges {
			t.Fatalf("unexpected privilege: %s", p)
		}
		return nil
	}

	if res := e.ExecuteStatement(influxql.MustParseStatement(`REVOKE ALL PRIVILEGES ON foo FROM susy`)); res.Err != nil {
		t.Fatal(res.Err)
	} else if res.Series != nil {
		t.Fatalf("unexpected rows: %#v", res.Series)
	}
}
// Ensure that executing an unsupported statement will panic.
func TestStatementExecutor_ExecuteStatement_Unsupported(t *testing.T) {
	var panicked bool
	func() {
		defer func() {
			if r := recover(); r != nil {
				panicked = true
			}
		}()

		// Execute a SELECT statement.
		NewStatementExecutor().ExecuteStatement(
			influxql.MustParseStatement(`SELECT count(field1) FROM db0`),
		)
	}()

	// Ensure that the executor panicked.
	if !panicked {
		t.Fatal("executor did not panic")
	}
}