influxdb/http/macro_test.go

617 lines
15 KiB
Go
Raw Normal View History

2018-09-11 23:13:15 +00:00
package http
import (
"bytes"
"context"
"io/ioutil"
"net/http"
2018-09-11 23:13:15 +00:00
"net/http/httptest"
"testing"
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/inmem"
kerrors "github.com/influxdata/influxdb/kit/errors"
"github.com/influxdata/influxdb/mock"
platformtesting "github.com/influxdata/influxdb/testing"
2018-09-11 23:13:15 +00:00
"github.com/julienschmidt/httprouter"
)
func TestMacroService_handleGetMacros(t *testing.T) {
type fields struct {
MacroService platform.MacroService
}
type args struct {
queryParams map[string][]string
}
2018-09-11 23:13:15 +00:00
type wants struct {
statusCode int
contentType string
body string
}
tests := []struct {
name string
fields fields
args args
2018-09-11 23:13:15 +00:00
wants wants
}{
{
name: "get all macros",
fields: fields{
&mock.MacroService{
FindMacrosF: func(ctx context.Context, filter platform.MacroFilter, opts ...platform.FindOptions) ([]*platform.Macro, error) {
2018-09-11 23:13:15 +00:00
return []*platform.Macro{
{
ID: platformtesting.MustIDBase16("6162207574726f71"),
2018-09-11 23:13:15 +00:00
Name: "macro-a",
Selected: []string{"b"},
Arguments: &platform.MacroArguments{
2018-09-11 23:13:15 +00:00
Type: "constant",
Values: platform.MacroConstantValues{"a", "b"},
},
},
{
ID: platformtesting.MustIDBase16("61726920617a696f"),
2018-09-11 23:13:15 +00:00
Name: "macro-b",
Selected: []string{"c"},
Arguments: &platform.MacroArguments{
2018-09-11 23:13:15 +00:00
Type: "map",
Values: platform.MacroMapValues{"a": "b", "c": "d"},
},
},
}, nil
},
},
},
wants: wants{
statusCode: http.StatusOK,
2018-09-11 23:13:15 +00:00
contentType: "application/json; charset=utf-8",
body: `{"macros":[{"id":"6162207574726f71","name":"macro-a","selected":["b"],"arguments":{"type":"constant","values":["a","b"]},"links":{"self":"/api/v2/macros/6162207574726f71"}},{"id":"61726920617a696f","name":"macro-b","selected":["c"],"arguments":{"type":"map","values":{"a":"b","c":"d"}},"links":{"self":"/api/v2/macros/61726920617a696f"}}],"links":{"self":"/api/v2/macros?descending=false&limit=20&offset=0"}}`,
2018-09-11 23:13:15 +00:00
},
},
{
name: "get all macros when there are none",
fields: fields{
&mock.MacroService{
FindMacrosF: func(ctx context.Context, filter platform.MacroFilter, opts ...platform.FindOptions) ([]*platform.Macro, error) {
return []*platform.Macro{}, nil
},
},
},
args: args{
map[string][]string{
"limit": []string{"1"},
},
},
wants: wants{
statusCode: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: `{"links":{"self":"/api/v2/macros?descending=false&limit=1&offset=0"},"macros":[]}`,
},
},
// todo(leodido) > activate whenever filtering functionality is done
// {
// name: "get all macros belonging to an org",
// fields: fields{
// &mock.MacroService{
// FindMacrosF: func(ctx context.Context, filter platform.MacroFilter, opts ...platform.FindOptions) ([]*platform.Macro, error) {
// return []*platform.Macro{
// {
// ID: platformtesting.MustIDBase16("6162207574726f71"),
// OrganizationID: platformtesting.MustIDBase16("0000000000000022"),
// Name: "macro-a",
// Selected: []string{"b"},
// Arguments: &platform.MacroArguments{
// Type: "constant",
// Values: platform.MacroConstantValues{"a", "b"},
// },
// },
// {
// ID: platformtesting.MustIDBase16("61726920617a696f"),
// OrganizationID: platformtesting.MustIDBase16("0000000000000016"),
// Name: "macro-b",
// Selected: []string{"c"},
// Arguments: &platform.MacroArguments{
// Type: "map",
// Values: platform.MacroMapValues{"a": "b", "c": "d"},
// },
// },
// }, nil
// },
// },
// },
// args: args{
// map[string][]string{
// "orgID": []string{"0000000000000022"},
// },
// },
// wants: wants{
// statusCode: http.StatusOK,
// contentType: "application/json; charset=utf-8",
// body: `{"macros":[{"id":"6162207574726f71","name":"macro-a","selected":["b"],"arguments":{"type":"constant","values":["a","b"]},"links":{"self":"/api/v2/macros/6162207574726f71"}}],"links":{"self":"/api/v2/macros?descending=false&limit=20&offset=0"}}`,
// },
// },
2018-09-11 23:13:15 +00:00
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
h := NewMacroHandler()
h.MacroService = tt.fields.MacroService
2018-09-11 23:13:15 +00:00
r := httptest.NewRequest("GET", "http://howdy.tld", nil)
qp := r.URL.Query()
for k, vs := range tt.args.queryParams {
for _, v := range vs {
qp.Add(k, v)
}
}
r.URL.RawQuery = qp.Encode()
2018-09-11 23:13:15 +00:00
w := httptest.NewRecorder()
h.handleGetMacros(w, r)
res := w.Result()
contentType := res.Header.Get("Content-Type")
body, _ := ioutil.ReadAll(res.Body)
2018-09-11 23:13:15 +00:00
if res.StatusCode != tt.wants.statusCode {
t.Errorf("%q. handleGetMacros() = %v, want %v", tt.name, res.StatusCode, tt.wants.statusCode)
2018-09-11 23:13:15 +00:00
}
if contentType != tt.wants.contentType {
t.Errorf("%q. handleGetMacros() = %v, want %v", tt.name, contentType, tt.wants.contentType)
2018-09-11 23:13:15 +00:00
}
if err := platformtesting.CompareJSON(string(body), tt.wants.body, tt.name, "handleGetMacros()"); err != nil {
t.Error(err)
2018-09-11 23:13:15 +00:00
}
})
}
}
func TestMacroService_handleGetMacro(t *testing.T) {
type fields struct {
MacroService platform.MacroService
}
type args struct {
id string
}
type wants struct {
statusCode int
contentType string
body string
}
tests := []struct {
name string
args args
fields fields
wants wants
}{
{
name: "get a single macro",
args: args{
id: "75650d0a636f6d70",
2018-09-11 23:13:15 +00:00
},
fields: fields{
&mock.MacroService{
FindMacroByIDF: func(ctx context.Context, id platform.ID) (*platform.Macro, error) {
return &platform.Macro{
ID: platformtesting.MustIDBase16("75650d0a636f6d70"),
2018-09-11 23:13:15 +00:00
Name: "macro-a",
Selected: []string{"b"},
Arguments: &platform.MacroArguments{
2018-09-11 23:13:15 +00:00
Type: "constant",
Values: platform.MacroConstantValues{"a", "b"},
},
}, nil
},
},
},
wants: wants{
statusCode: 200,
contentType: "application/json; charset=utf-8",
body: `{"id":"75650d0a636f6d70","name":"macro-a","selected":["b"],"arguments":{"type":"constant","values":["a","b"]},"links":{"self":"/api/v2/macros/75650d0a636f6d70"}}
2018-09-11 23:13:15 +00:00
`,
},
},
{
name: "get a non-existant macro",
args: args{
id: "75650d0a636f6d70",
2018-09-11 23:13:15 +00:00
},
fields: fields{
&mock.MacroService{
FindMacroByIDF: func(ctx context.Context, id platform.ID) (*platform.Macro, error) {
return nil, kerrors.Errorf(kerrors.NotFound, "macro with ID %v not found", id)
},
},
},
wants: wants{
statusCode: 404,
contentType: "",
body: ``,
},
},
{
name: "request an invalid macro ID",
args: args{
id: "baz",
},
fields: fields{
&mock.MacroService{
FindMacroByIDF: func(ctx context.Context, id platform.ID) (*platform.Macro, error) {
return nil, nil
},
},
},
wants: wants{
statusCode: 400,
2018-12-15 15:33:54 +00:00
contentType: "application/json; charset=utf-8",
body: `{"code":"invalid","message":"An internal error has occurred.","error":"id must have a length of 16 bytes"}`,
},
},
2018-09-11 23:13:15 +00:00
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
h := NewMacroHandler()
h.MacroService = tt.fields.MacroService
r := httptest.NewRequest("GET", "http://howdy.tld", nil)
r = r.WithContext(context.WithValue(
context.TODO(),
httprouter.ParamsKey,
httprouter.Params{
{
Key: "id",
Value: tt.args.id,
},
}))
w := httptest.NewRecorder()
h.handleGetMacro(w, r)
res := w.Result()
contentType := res.Header.Get("Content-Type")
bodyBytes, _ := ioutil.ReadAll(res.Body)
body := string(bodyBytes[:])
if res.StatusCode != tt.wants.statusCode {
t.Errorf("got = %v, want %v", res.StatusCode, tt.wants.statusCode)
}
if contentType != tt.wants.contentType {
t.Errorf("got = %v, want %v", contentType, tt.wants.contentType)
}
if body != tt.wants.body {
t.Errorf("got = %v, want %v", body, tt.wants.body)
}
})
}
}
func TestMacroService_handlePostMacro(t *testing.T) {
type fields struct {
MacroService platform.MacroService
}
type args struct {
macro string
}
type wants struct {
statusCode int
contentType string
body string
}
tests := []struct {
name string
fields fields
args args
wants wants
}{
{
name: "create a new macro",
fields: fields{
&mock.MacroService{
CreateMacroF: func(ctx context.Context, m *platform.Macro) error {
m.ID = platformtesting.MustIDBase16("75650d0a636f6d70")
2018-09-11 23:13:15 +00:00
return nil
},
},
},
args: args{
macro: `
{
"name": "my-great-macro",
"arguments": {
"type": "constant",
"values": [
"bar",
"foo"
]
},
"selected": [
"'foo'"
]
}
`,
},
wants: wants{
statusCode: 201,
contentType: "application/json; charset=utf-8",
body: `{"id":"75650d0a636f6d70","name":"my-great-macro","selected":["'foo'"],"arguments":{"type":"constant","values":["bar","foo"]},"links":{"self":"/api/v2/macros/75650d0a636f6d70"}}
2018-09-11 23:13:15 +00:00
`,
},
},
{
name: "create a macro with invalid fields",
fields: fields{
&mock.MacroService{
CreateMacroF: func(ctx context.Context, m *platform.Macro) error {
m.ID = platformtesting.MustIDBase16("0")
2018-09-11 23:13:15 +00:00
return nil
},
},
},
args: args{
macro: `{"data": "nonsense"}`,
},
wants: wants{
statusCode: 422,
contentType: "",
body: "",
},
},
{
name: "create a macro with invalid json",
fields: fields{
&mock.MacroService{
CreateMacroF: func(ctx context.Context, m *platform.Macro) error {
m.ID = platformtesting.MustIDBase16("0")
2018-09-11 23:13:15 +00:00
return nil
},
},
},
args: args{
macro: `howdy`,
},
wants: wants{
statusCode: 400,
contentType: "",
body: "",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
h := NewMacroHandler()
h.MacroService = tt.fields.MacroService
r := httptest.NewRequest("GET", "http://howdy.tld", bytes.NewReader([]byte(tt.args.macro)))
w := httptest.NewRecorder()
h.handlePostMacro(w, r)
res := w.Result()
contentType := res.Header.Get("Content-Type")
bodyBytes, _ := ioutil.ReadAll(res.Body)
body := string(bodyBytes[:])
if res.StatusCode != tt.wants.statusCode {
t.Errorf("got = %v, want %v", res.StatusCode, tt.wants.statusCode)
}
if contentType != tt.wants.contentType {
t.Errorf("got = %v, want %v", contentType, tt.wants.contentType)
}
if body != tt.wants.body {
t.Errorf("got = %v, want %v", body, tt.wants.body)
}
})
}
}
func TestMacroService_handlePatchMacro(t *testing.T) {
type fields struct {
MacroService platform.MacroService
}
type args struct {
id string
update string
}
type wants struct {
statusCode int
contentType string
body string
}
tests := []struct {
name string
fields fields
args args
wants wants
}{
{
name: "update a macro name",
fields: fields{
&mock.MacroService{
UpdateMacroF: func(ctx context.Context, id platform.ID, u *platform.MacroUpdate) (*platform.Macro, error) {
return &platform.Macro{
ID: platformtesting.MustIDBase16("75650d0a636f6d70"),
2018-09-11 23:13:15 +00:00
Name: "new-name",
Arguments: &platform.MacroArguments{
2018-09-11 23:13:15 +00:00
Type: "constant",
Values: platform.MacroConstantValues{},
},
Selected: []string{},
}, nil
},
},
},
args: args{
id: "75650d0a636f6d70",
2018-09-11 23:13:15 +00:00
update: `{"name": "new-name"}`,
},
wants: wants{
statusCode: 200,
contentType: "application/json; charset=utf-8",
body: `{"id":"75650d0a636f6d70","name":"new-name","selected":[],"arguments":{"type":"constant","values":[]},"links":{"self":"/api/v2/macros/75650d0a636f6d70"}}
2018-09-11 23:13:15 +00:00
`,
},
},
{
name: "with an empty json body",
fields: fields{
&mock.MacroService{},
},
args: args{
id: "75650d0a636f6d70",
2018-09-11 23:13:15 +00:00
update: `{}`,
},
wants: wants{
statusCode: 422,
contentType: "",
body: ``,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
h := NewMacroHandler()
h.MacroService = tt.fields.MacroService
r := httptest.NewRequest("GET", "http://howdy.tld", bytes.NewReader([]byte(tt.args.update)))
r = r.WithContext(context.WithValue(
context.TODO(),
httprouter.ParamsKey,
httprouter.Params{
{
Key: "id",
Value: tt.args.id,
},
}))
w := httptest.NewRecorder()
h.handlePatchMacro(w, r)
res := w.Result()
contentType := res.Header.Get("Content-Type")
bodyBytes, _ := ioutil.ReadAll(res.Body)
body := string(bodyBytes[:])
if res.StatusCode != tt.wants.statusCode {
t.Errorf("got = %v, want %v", res.StatusCode, tt.wants.statusCode)
}
if contentType != tt.wants.contentType {
t.Errorf("got = %v, want %v", contentType, tt.wants.contentType)
}
if body != tt.wants.body {
t.Errorf("got = %v, want %v", body, tt.wants.body)
}
})
}
}
func TestMacroService_handleDeleteMacro(t *testing.T) {
type fields struct {
MacroService platform.MacroService
}
type args struct {
id string
}
type wants struct {
statusCode int
2018-09-11 23:13:15 +00:00
}
tests := []struct {
name string
fields fields
args args
wants wants
}{
{
name: "delete a macro",
fields: fields{
&mock.MacroService{
DeleteMacroF: func(ctx context.Context, id platform.ID) error {
return nil
},
},
},
args: args{
id: "75650d0a636f6d70",
2018-09-11 23:13:15 +00:00
},
wants: wants{
statusCode: 204,
},
},
{
name: "delete a non-existant macro",
fields: fields{
&mock.MacroService{
DeleteMacroF: func(ctx context.Context, id platform.ID) error {
return kerrors.Errorf(kerrors.NotFound, "macro with ID %v not found", id)
},
},
},
args: args{
id: "75650d0a636f6d70",
2018-09-11 23:13:15 +00:00
},
wants: wants{
statusCode: 404,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
h := NewMacroHandler()
h.MacroService = tt.fields.MacroService
r := httptest.NewRequest("GET", "http://howdy.tld", nil)
r = r.WithContext(context.WithValue(
context.TODO(),
httprouter.ParamsKey,
httprouter.Params{
{
Key: "id",
Value: tt.args.id,
},
}))
w := httptest.NewRecorder()
h.handleDeleteMacro(w, r)
statusCode := w.Result().StatusCode
if statusCode != tt.wants.statusCode {
t.Errorf("got = %v, want %v", statusCode, tt.wants.statusCode)
}
})
}
}
2018-12-13 14:57:00 +00:00
func initMacroService(f platformtesting.MacroFields, t *testing.T) (platform.MacroService, string, func()) {
t.Helper()
svc := inmem.NewService()
svc.IDGenerator = f.IDGenerator
ctx := context.Background()
for _, macro := range f.Macros {
if err := svc.ReplaceMacro(ctx, macro); err != nil {
t.Fatalf("failed to populate macros")
}
}
handler := NewMacroHandler()
handler.MacroService = svc
server := httptest.NewServer(handler)
client := MacroService{
Addr: server.URL,
}
done := server.Close
2018-12-13 14:57:00 +00:00
return &client, inmem.OpPrefix, done
}
func TestMacroService(t *testing.T) {
platformtesting.MacroService(initMacroService, t)
}