influxdb/cmd/influx/bucket_test.go

482 lines
12 KiB
Go

package main
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"os"
"reflect"
"testing"
"time"
"github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/mock"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCmdBucket(t *testing.T) {
orgID := influxdb.ID(9000)
fakeSVCFn := func(svc influxdb.BucketService) bucketSVCsFn {
return func() (influxdb.BucketService, influxdb.OrganizationService, error) {
return svc, &mock.OrganizationService{
FindOrganizationF: func(ctx context.Context, filter influxdb.OrganizationFilter) (*influxdb.Organization, error) {
return &influxdb.Organization{ID: orgID, Name: "influxdata"}, nil
},
}, nil
}
}
t.Run("create", func(t *testing.T) {
tests := []struct {
name string
expectedBucket influxdb.Bucket
flags []string
envVars map[string]string
}{
{
name: "basic just name",
flags: []string{"--name=new name", "--org=org name"},
expectedBucket: influxdb.Bucket{
Name: "new name",
OrgID: orgID,
},
},
{
name: "with description and retention period",
flags: []string{
"--name=new name",
"--description=desc",
"--retention=1m",
"--org=org name",
},
expectedBucket: influxdb.Bucket{
Name: "new name",
Description: "desc",
RetentionPeriod: time.Minute,
OrgID: orgID,
},
},
{
name: "shorts",
flags: []string{
"-n=new name",
"-d=desc",
"-r=1m",
"-o=org name",
},
expectedBucket: influxdb.Bucket{
Name: "new name",
Description: "desc",
RetentionPeriod: time.Minute,
OrgID: orgID,
},
},
{
name: "env vars",
flags: []string{
"-d=desc",
"-r=1m",
"-o=org name",
},
envVars: map[string]string{"INFLUX_BUCKET_NAME": "new name"},
expectedBucket: influxdb.Bucket{
Name: "new name",
Description: "desc",
RetentionPeriod: time.Minute,
OrgID: orgID,
},
},
}
cmdFn := func(expectedBkt influxdb.Bucket) func(*globalFlags, genericCLIOpts) *cobra.Command {
svc := mock.NewBucketService()
svc.CreateBucketFn = func(ctx context.Context, bucket *influxdb.Bucket) error {
if expectedBkt != *bucket {
return fmt.Errorf("unexpected bucket;\n\twant= %+v\n\tgot= %+v", expectedBkt, *bucket)
}
return nil
}
return func(g *globalFlags, opt genericCLIOpts) *cobra.Command {
return newCmdBucketBuilder(fakeSVCFn(svc), opt).cmd()
}
}
for _, tt := range tests {
fn := func(t *testing.T) {
defer addEnvVars(t, tt.envVars)()
builder := newInfluxCmdBuilder(
in(new(bytes.Buffer)),
out(ioutil.Discard),
)
cmd := builder.cmd(cmdFn(tt.expectedBucket))
cmd.SetArgs(append([]string{"bucket", "create"}, tt.flags...))
require.NoError(t, cmd.Execute())
}
t.Run(tt.name, fn)
}
})
t.Run("delete", func(t *testing.T) {
tests := []struct {
name string
expectedID influxdb.ID
flags []string
}{
{
name: "with description and retention period",
expectedID: influxdb.ID(1),
flags: []string{"--id=" + influxdb.ID(1).String()},
},
{
name: "shorts",
expectedID: influxdb.ID(1),
flags: []string{"-i=" + influxdb.ID(1).String()},
},
{
name: "with name and org name",
expectedID: influxdb.ID(1),
flags: []string{"--name=n1", "--org=org1"},
},
{
name: "with name and org name short",
expectedID: influxdb.ID(1),
flags: []string{"-n=n1", "-o=org1"},
},
{
name: "with name and org id",
expectedID: influxdb.ID(1),
flags: []string{"--name=n1", "--org-id=" + influxdb.ID(3).String()},
},
}
cmdFn := func(expectedID influxdb.ID) func(*globalFlags, genericCLIOpts) *cobra.Command {
svc := mock.NewBucketService()
svc.FindBucketByIDFn = func(ctx context.Context, id influxdb.ID) (*influxdb.Bucket, error) {
return &influxdb.Bucket{ID: id}, nil
}
svc.FindBucketFn = func(ctx context.Context, filter influxdb.BucketFilter) (*influxdb.Bucket, error) {
if filter.ID != nil {
return &influxdb.Bucket{ID: *filter.ID}, nil
}
if filter.Name != nil {
return &influxdb.Bucket{ID: expectedID}, nil
}
return nil, nil
}
svc.DeleteBucketFn = func(ctx context.Context, id influxdb.ID) error {
if expectedID != id {
return fmt.Errorf("unexpected id:\n\twant= %s\n\tgot= %s", expectedID, id)
}
return nil
}
return func(g *globalFlags, opt genericCLIOpts) *cobra.Command {
return newCmdBucketBuilder(fakeSVCFn(svc), opt).cmd()
}
}
for _, tt := range tests {
fn := func(t *testing.T) {
defer addEnvVars(t, envVarsZeroMap)()
outBuf := new(bytes.Buffer)
defer func() {
if t.Failed() && outBuf.Len() > 0 {
t.Log(outBuf.String())
}
}()
builder := newInfluxCmdBuilder(
in(new(bytes.Buffer)),
out(outBuf),
)
cmd := builder.cmd(cmdFn(tt.expectedID))
cmd.SetArgs(append([]string{"bucket", "delete"}, tt.flags...))
require.NoError(t, cmd.Execute())
}
t.Run(tt.name, fn)
}
})
t.Run("list", func(t *testing.T) {
type called struct {
name string
id influxdb.ID
orgID influxdb.ID
org string
}
tests := []struct {
name string
expected called
flags []string
command string
envVars map[string]string
}{
{
name: "org id",
flags: []string{"--org-id=" + influxdb.ID(3).String()},
envVars: envVarsZeroMap,
expected: called{orgID: 3},
},
{
name: "id",
flags: []string{
"--id=" + influxdb.ID(2).String(),
"--org-id=" + influxdb.ID(3).String(),
},
envVars: envVarsZeroMap,
expected: called{
id: 2,
orgID: 3,
},
},
{
name: "org",
flags: []string{"--org=rg"},
envVars: envVarsZeroMap,
expected: called{org: "rg"},
},
{
name: "name",
flags: []string{"--org=rg", "--name=name1"},
envVars: envVarsZeroMap,
expected: called{org: "rg", name: "name1"},
},
{
name: "shorts",
flags: []string{
"-o=rg",
"-n=name1",
"-i=" + influxdb.ID(1).String(),
},
envVars: envVarsZeroMap,
expected: called{org: "rg", name: "name1", id: 1},
},
{
name: "env vars",
envVars: map[string]string{
"INFLUX_ORG": "rg",
"INFLUX_BUCKET_NAME": "name1",
},
flags: []string{"-i=" + influxdb.ID(1).String()},
expected: called{org: "rg", name: "name1", id: 1},
},
{
name: "env vars 2",
envVars: map[string]string{
"INFLUX_ORG": "",
"INFLUX_ORG_ID": influxdb.ID(2).String(),
"INFLUX_BUCKET_NAME": "name1",
},
flags: []string{"-i=" + influxdb.ID(1).String()},
expected: called{orgID: 2, name: "name1", id: 1},
},
{
name: "ls alias",
command: "ls",
envVars: envVarsZeroMap,
flags: []string{"--org-id=" + influxdb.ID(3).String()},
expected: called{orgID: 3},
},
{
name: "find alias",
command: "find",
envVars: envVarsZeroMap,
flags: []string{"--org-id=" + influxdb.ID(3).String()},
expected: called{orgID: 3},
},
}
cmdFn := func() (func(*globalFlags, genericCLIOpts) *cobra.Command, *called) {
calls := new(called)
svc := mock.NewBucketService()
svc.FindBucketsFn = func(ctx context.Context, f influxdb.BucketFilter, opt ...influxdb.FindOptions) ([]*influxdb.Bucket, int, error) {
if f.ID != nil {
calls.id = *f.ID
}
if f.OrganizationID != nil {
calls.orgID = *f.OrganizationID
}
if f.Name != nil {
calls.name = *f.Name
}
if f.Org != nil {
calls.org = *f.Org
}
return nil, 0, nil
}
return func(g *globalFlags, opt genericCLIOpts) *cobra.Command {
return newCmdBucketBuilder(fakeSVCFn(svc), opt).cmd()
}, calls
}
for _, tt := range tests {
fn := func(t *testing.T) {
defer addEnvVars(t, tt.envVars)()
builder := newInfluxCmdBuilder(
in(new(bytes.Buffer)),
out(ioutil.Discard),
)
cmdFn, calls := cmdFn()
cmd := builder.cmd(cmdFn)
if tt.command == "" {
tt.command = "list"
}
cmd.SetArgs(append([]string{"bucket", tt.command}, tt.flags...))
require.NoError(t, cmd.Execute())
assert.Equal(t, tt.expected, *calls)
}
t.Run(tt.name, fn)
}
})
t.Run("update", func(t *testing.T) {
tests := []struct {
name string
expected influxdb.BucketUpdate
flags []string
envVars map[string]string
}{
{
name: "basic just name",
flags: []string{
"--id=" + influxdb.ID(3).String(),
"--name=new name",
},
expected: influxdb.BucketUpdate{
Name: strPtr("new name"),
},
},
{
name: "with all fields",
flags: []string{
"--id=" + influxdb.ID(3).String(),
"--name=new name",
"--description=desc",
"--retention=1m",
},
expected: influxdb.BucketUpdate{
Name: strPtr("new name"),
Description: strPtr("desc"),
RetentionPeriod: durPtr(time.Minute),
},
},
{
name: "shorts",
flags: []string{
"-i=" + influxdb.ID(3).String(),
"-n=new name",
"-d=desc",
"-r=1m",
},
expected: influxdb.BucketUpdate{
Name: strPtr("new name"),
Description: strPtr("desc"),
RetentionPeriod: durPtr(time.Minute),
},
},
{
name: "env var",
flags: []string{
"-i=" + influxdb.ID(3).String(),
"-d=desc",
"-r=1m",
},
envVars: map[string]string{"INFLUX_BUCKET_NAME": "new name"},
expected: influxdb.BucketUpdate{
Name: strPtr("new name"),
Description: strPtr("desc"),
RetentionPeriod: durPtr(time.Minute),
},
},
}
cmdFn := func(expectedUpdate influxdb.BucketUpdate) func(*globalFlags, genericCLIOpts) *cobra.Command {
svc := mock.NewBucketService()
svc.UpdateBucketFn = func(ctx context.Context, id influxdb.ID, upd influxdb.BucketUpdate) (*influxdb.Bucket, error) {
if id != 3 {
return nil, fmt.Errorf("unexpecte id:\n\twant= %s\n\tgot= %s", influxdb.ID(3), id)
}
if !reflect.DeepEqual(expectedUpdate, upd) {
return nil, fmt.Errorf("unexpected bucket update;\n\twant= %+v\n\tgot= %+v", expectedUpdate, upd)
}
return &influxdb.Bucket{}, nil
}
return func(g *globalFlags, opt genericCLIOpts) *cobra.Command {
return newCmdBucketBuilder(fakeSVCFn(svc), opt).cmd()
}
}
for _, tt := range tests {
fn := func(t *testing.T) {
defer addEnvVars(t, tt.envVars)()
builder := newInfluxCmdBuilder(
in(new(bytes.Buffer)),
out(ioutil.Discard),
)
cmd := builder.cmd(cmdFn(tt.expected))
cmd.SetArgs(append([]string{"bucket", "update"}, tt.flags...))
require.NoError(t, cmd.Execute())
}
t.Run(tt.name, fn)
}
})
}
func strPtr(s string) *string {
return &s
}
func durPtr(d time.Duration) *time.Duration {
return &d
}
func addEnvVars(t *testing.T, envVars map[string]string) func() {
t.Helper()
var initialEnvVars []struct{ key, val string }
for key, val := range envVars {
if k := os.Getenv(key); k != "" {
initialEnvVars = append(initialEnvVars, struct{ key, val string }{
key: key,
val: k,
})
}
require.NoError(t, os.Setenv(key, val))
}
return func() {
for key := range envVars {
require.NoError(t, os.Unsetenv(key))
}
for _, envVar := range initialEnvVars {
require.NoError(t, os.Setenv(envVar.key, envVar.val))
}
}
}