influxdb/cmd/influx/config/config_test.go

835 lines
15 KiB
Go

package config
import (
"bytes"
"testing"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/google/go-cmp/cmp"
influxtesting "github.com/influxdata/influxdb/v2/testing"
)
func TestWriteConfigs(t *testing.T) {
cases := []struct {
name string
err *errors.Error
pp Configs
result string
}{
{
name: "bad name -",
err: &errors.Error{
Code: errors.EInvalid,
Msg: `"-" is not a valid config name`,
},
},
{
name: "bad name create",
err: &errors.Error{
Code: errors.EInvalid,
Msg: `"create" is not a valid config name`,
},
},
{
name: "new config",
pp: Configs{
"default": Config{
Token: "token1",
Org: "org1",
Host: "http://localhost:8086",
Active: true,
},
},
result: `[default]
url = "http://localhost:8086"
token = "token1"
org = "org1"
active = true` + commentedStr,
},
{
name: "multiple",
pp: Configs{
"config1": Config{
Token: "token1",
Host: "host1",
},
"config2": Config{
Token: "token2",
Host: "host2",
Org: "org2",
Active: true,
},
"config3": Config{
Token: "token3",
Host: "host3",
Org: "org3",
},
},
result: `[config1]
url = "host1"
token = "token1"
org = ""
[config2]
url = "host2"
token = "token2"
org = "org2"
active = true
[config3]
url = "host3"
token = "token3"
org = "org3"` + commentedStr,
},
}
for _, c := range cases {
var b1 bytes.Buffer
err := (baseRW{w: &b1}).writeConfigs(c.pp)
influxtesting.ErrorsEqual(t, err, err)
if c.err == nil {
if diff := cmp.Diff(c.result, b1.String()); diff != "" {
t.Fatalf("write configs %s err, diff %s", c.name, diff)
}
}
}
}
var commentedStr = `
#
# [eu-central]
# url = "https://eu-central-1-1.aws.cloud2.influxdata.com"
# token = "XXX"
# org = ""
#
# [us-central]
# url = "https://us-central1-1.gcp.cloud2.influxdata.com"
# token = "XXX"
# org = ""
#
# [us-west]
# url = "https://us-west-2-1.aws.cloud2.influxdata.com"
# token = "XXX"
# org = ""
`
func TestParseActiveConfig(t *testing.T) {
cases := []struct {
name string
hasErr bool
src string
p Config
}{
{
name: "bad src",
src: "bad [toml",
hasErr: true,
},
{
name: "nothing",
hasErr: true,
},
{
name: "conflicted",
hasErr: true,
src: `
[a1]
url = "host1"
active =true
[a2]
url = "host2"
active = true
`,
},
{
name: "one active",
hasErr: false,
src: `
[a1]
url = "host1"
[a2]
url = "host2"
active = true
[a3]
url = "host3"
[a4]
url = "host4"
`,
p: Config{
Name: "a2",
Host: "host2",
Active: true,
},
},
}
for _, c := range cases {
r := bytes.NewBufferString(c.src)
p, err := ParseActiveConfig(r)
if c.hasErr {
if err == nil {
t.Fatalf("parse active config %q failed, should have error, got nil", c.name)
}
continue
}
if diff := cmp.Diff(p, c.p); diff != "" {
t.Fatalf("parse active config %s failed, diff %s", c.name, diff)
}
}
}
func TestParsePreviousActiveConfig(t *testing.T) {
cases := []struct {
name string
hasErr bool
src string
p Config
}{
{
name: "bad src",
src: "bad [toml",
hasErr: true,
},
{
name: "nothing",
hasErr: true,
},
{
name: "conflicted",
hasErr: true,
src: `
[a1]
url = "host1"
previous =true
[a2]
url = "host2"
previous = true
`,
},
{
name: "one previous active",
hasErr: false,
src: `
[a1]
url = "host1"
[a2]
url = "host2"
previous = true
[a3]
url = "host3"
[a4]
url = "host4"
`,
p: Config{
Name: "a2",
Host: "host2",
PreviousActive: true,
},
},
}
for _, c := range cases {
r := bytes.NewBufferString(c.src)
p, err := (baseRW{r: r}).parsePreviousActive()
if c.hasErr {
if err == nil {
t.Fatalf("parse previous active config %q failed, should have error, got nil", c.name)
}
continue
}
if diff := cmp.Diff(p, c.p); diff != "" {
t.Fatalf("parse previous active config %s failed, diff %s", c.name, diff)
}
}
}
func TestConfigsSwith(t *testing.T) {
cases := []struct {
name string
old Configs
new Configs
target string
err error
}{
{
name: "not found",
target: "p1",
old: Configs{
"a1": {Host: "host1"},
"a2": {Host: "host2"},
},
new: Configs{
"a1": {Host: "host1"},
"a2": {Host: "host2"},
},
err: &errors.Error{
Code: errors.ENotFound,
Msg: `config "p1" is not found`,
},
},
{
name: "regular switch",
target: "a1",
old: Configs{
"a1": {Host: "host1"},
"a2": {Host: "host2"},
"a3": {Host: "host3", Active: true},
},
new: Configs{
"a1": {Host: "host1", Active: true},
"a2": {Host: "host2"},
"a3": {Host: "host3", PreviousActive: true},
},
err: nil,
},
{
name: "regular to current active", // nothing should be changed
target: "a3",
old: Configs{
"a1": {Host: "host1"},
"a2": {Host: "host2"},
"a3": {Host: "host3", Active: true},
},
new: Configs{
"a1": {Host: "host1"},
"a2": {Host: "host2"},
"a3": {Host: "host3", Active: true},
},
err: nil,
},
}
for _, c := range cases {
err := c.old.Switch(c.target)
influxtesting.ErrorsEqual(t, err, c.err)
if diff := cmp.Diff(c.old, c.new); diff != "" {
t.Fatalf("switch config %s failed, diff %s", c.name, diff)
}
}
}
func TestConfigCreate(t *testing.T) {
cases := []struct {
name string
exists Configs
src Config
err error
result Config
stored Configs
}{
{
name: "invalid name",
err: &errors.Error{
Code: errors.EInvalid,
Msg: "config name is empty",
},
},
{
name: "new",
src: Config{
Name: "default",
Host: "host1",
Org: "org1",
Token: "tok1",
},
result: Config{
Name: "default",
Host: "host1",
Org: "org1",
Token: "tok1",
},
stored: Configs{
"default": {
Name: "default",
Host: "host1",
Org: "org1",
Token: "tok1",
},
},
},
{
name: "new active",
src: Config{
Name: "default",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
result: Config{
Name: "default",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
stored: Configs{
"default": {
Name: "default",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
},
},
{
name: "conflict",
exists: Configs{
"default": {
Name: "default",
Host: "host1",
},
},
src: Config{
Name: "default",
Host: "host1",
},
err: &errors.Error{
Code: errors.EConflict,
Msg: `config "default" already exists`,
},
},
{
name: "existing",
exists: Configs{
"default": {
Name: "default",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
},
src: Config{
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
result: Config{
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
stored: Configs{
"default": {
Name: "default",
Host: "host1",
Org: "org1",
Token: "tok1",
PreviousActive: true,
},
"a1": {
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
},
},
}
for _, c := range cases {
svc, store := newBufferSVC()
_ = store.writeConfigs(c.exists)
result, err := svc.CreateConfig(c.src)
influxtesting.ErrorsEqual(t, err, c.err)
if err == nil {
if diff := cmp.Diff(result, c.result); diff != "" {
t.Fatalf("create config %s failed, diff %s", c.name, diff)
}
stored, err := store.ListConfigs()
if err != nil {
t.Fatalf("create config %s to list result, err %s", c.name, err.Error())
}
if diff := cmp.Diff(stored, c.stored); diff != "" {
t.Fatalf("create config %s failed, diff %s", c.name, diff)
}
}
}
}
func TestConfigSwitch(t *testing.T) {
cases := []struct {
name string
exists Configs
src string
err error
result Config
stored Configs
}{
{
name: "empty",
err: &errors.Error{
Code: errors.ENotFound,
Msg: `config "" is not found`,
},
},
{
name: "not found",
src: "default",
err: &errors.Error{
Code: errors.ENotFound,
Msg: `config "default" is not found`,
},
},
{
name: "regular",
exists: Configs{
"a1": {
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
},
"a2": {
Name: "a2",
Host: "host2",
Org: "org2",
Token: "tok2",
Active: true,
},
},
src: "a1",
result: Config{
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
stored: Configs{
"a1": {
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
"a2": {
Name: "a2",
Host: "host2",
Org: "org2",
Token: "tok2",
PreviousActive: true,
},
},
},
{
name: "switch back",
exists: Configs{
"a1": {
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
PreviousActive: true,
},
"a2": {
Name: "a2",
Host: "host2",
Org: "org2",
Token: "tok2",
Active: true,
},
},
src: "-",
result: Config{
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
stored: Configs{
"a1": {
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
"a2": {
Name: "a2",
Host: "host2",
Org: "org2",
Token: "tok2",
PreviousActive: true,
},
},
},
{
name: "switch back with no previous",
exists: Configs{
"a1": {
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
},
"a2": {
Name: "a2",
Host: "host2",
Org: "org2",
Token: "tok2",
Active: true,
},
},
src: "-",
err: &errors.Error{
Code: errors.ENotFound,
Msg: "previous activated config is not found",
},
},
}
for _, c := range cases {
svc, store := newBufferSVC()
_ = store.writeConfigs(c.exists)
result, err := svc.SwitchActive(c.src)
influxtesting.ErrorsEqual(t, err, c.err)
if err == nil {
if diff := cmp.Diff(result, c.result); diff != "" {
t.Fatalf("switch config %s failed, diff %s", c.name, diff)
}
stored, err := store.ListConfigs()
if err != nil {
t.Fatalf("switch config %s to list result, err %s", c.name, err.Error())
}
if diff := cmp.Diff(stored, c.stored); diff != "" {
t.Fatalf("switch config %s failed, diff %s", c.name, diff)
}
}
}
}
func TestConfigUpdate(t *testing.T) {
cases := []struct {
name string
exists Configs
src Config
err error
result Config
stored Configs
}{
{
name: "empty",
err: &errors.Error{
Code: errors.ENotFound,
Msg: `config "" is not found`,
},
},
{
name: "not found",
src: Config{
Name: "default",
Host: "host1",
Org: "org1",
Token: "tok1",
},
err: &errors.Error{
Code: errors.ENotFound,
Msg: `config "default" is not found`,
},
},
{
name: "regular",
exists: Configs{
"a1": {
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
},
"a2": {
Name: "a2",
Host: "host2",
Org: "org2",
Token: "tok2",
Active: true,
},
},
src: Config{
Name: "a1",
Host: "host11",
Org: "org11",
Token: "tok11",
Active: true,
},
result: Config{
Name: "a1",
Host: "host11",
Org: "org11",
Token: "tok11",
Active: true,
},
stored: Configs{
"a1": {
Name: "a1",
Host: "host11",
Org: "org11",
Token: "tok11",
Active: true,
},
"a2": {
Name: "a2",
Host: "host2",
Org: "org2",
Token: "tok2",
PreviousActive: true,
},
},
},
}
for _, c := range cases {
svc, store := newBufferSVC()
_ = store.writeConfigs(c.exists)
result, err := svc.UpdateConfig(c.src)
influxtesting.ErrorsEqual(t, err, c.err)
if err == nil {
if diff := cmp.Diff(result, c.result); diff != "" {
t.Fatalf("update config %s failed, diff %s", c.name, diff)
}
stored, err := store.ListConfigs()
if err != nil {
t.Fatalf("update config %s to list result, err %s", c.name, err.Error())
}
if diff := cmp.Diff(stored, c.stored); diff != "" {
t.Fatalf("update config %s failed, diff %s", c.name, diff)
}
}
}
}
func TestConfigDelete(t *testing.T) {
cases := []struct {
name string
exists Configs
target string
err error
result Config
stored Configs
}{
{
name: "empty",
err: &errors.Error{
Code: errors.ENotFound,
Msg: `config "" is not found`,
},
},
{
name: "not found",
target: "bad",
exists: Configs{
"default": {
Name: "default",
Host: "host1",
},
},
err: &errors.Error{
Code: errors.ENotFound,
Msg: `config "bad" is not found`,
},
},
{
name: "regular",
exists: Configs{
"default": {
Name: "default",
Host: "host1",
},
},
target: "default",
result: Config{
Name: "default",
Host: "host1",
},
stored: Configs{},
},
{
name: "more than 1",
exists: Configs{
"a1": {
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
"a2": {
Host: "host2",
Org: "org2",
Token: "tok2",
},
},
target: "a1",
result: Config{
Name: "a1",
Host: "host1",
Org: "org1",
Token: "tok1",
Active: true,
},
stored: Configs{
"a2": {
Active: true,
Name: "a2",
Host: "host2",
Org: "org2",
Token: "tok2",
},
},
},
}
for _, c := range cases {
fn := func(t *testing.T) {
svc, store := newBufferSVC()
_ = store.writeConfigs(c.exists)
result, err := svc.DeleteConfig(c.target)
influxtesting.ErrorsEqual(t, err, c.err)
if err == nil {
if diff := cmp.Diff(result, c.result); diff != "" {
t.Fatalf("delete config %s failed, diff %s", c.name, diff)
}
stored, err := store.ListConfigs()
if err != nil {
t.Fatalf("delete config %s to list result, err %s", c.name, err.Error())
}
if diff := cmp.Diff(stored, c.stored); diff != "" {
t.Fatalf("delete config %s failed, diff %s", c.name, diff)
}
}
}
t.Run(c.name, fn)
}
}
func newBufferSVC() (Service, *bytesStore) {
store := new(bytesStore)
return newConfigsSVC(store), store
}
type bytesStore struct {
data []byte
}
func (s *bytesStore) writeConfigs(cfgs Configs) error {
var b bytes.Buffer
if err := (baseRW{w: &b}).writeConfigs(cfgs); err != nil {
return err
}
s.data = b.Bytes()
return nil
}
func (s *bytesStore) ListConfigs() (Configs, error) {
return baseRW{
r: bytes.NewBuffer(s.data),
}.ListConfigs()
}
func (s *bytesStore) parsePreviousActive() (Config, error) {
return (baseRW{
r: bytes.NewBuffer(s.data),
}).parsePreviousActive()
}