influxdb/http/variable_test.go

1031 lines
28 KiB
Go

package http
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"time"
"github.com/influxdata/httprouter"
platform "github.com/influxdata/influxdb/v2"
platform2 "github.com/influxdata/influxdb/v2/kit/platform"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
kithttp "github.com/influxdata/influxdb/v2/kit/transport/http"
"github.com/influxdata/influxdb/v2/kv"
"github.com/influxdata/influxdb/v2/mock"
"github.com/influxdata/influxdb/v2/tenant"
itesting "github.com/influxdata/influxdb/v2/testing"
"go.uber.org/zap/zaptest"
)
var faketime = time.Date(2006, 5, 4, 1, 2, 3, 0, time.UTC)
// NewMockVariableBackend returns a VariableBackend with mock services.
func NewMockVariableBackend(t *testing.T) *VariableBackend {
return &VariableBackend{
HTTPErrorHandler: kithttp.NewErrorHandler(zaptest.NewLogger(t)),
log: zaptest.NewLogger(t),
VariableService: mock.NewVariableService(),
LabelService: mock.NewLabelService(),
}
}
func TestVariableService_handleGetVariables(t *testing.T) {
type fields struct {
VariableService platform.VariableService
LabelService platform.LabelService
}
type args struct {
queryParams map[string][]string
}
type wants struct {
statusCode int
contentType string
body string
}
tests := []struct {
name string
fields fields
args args
wants wants
}{
{
name: "get all variables",
fields: fields{
&mock.VariableService{
FindVariablesF: func(ctx context.Context, filter platform.VariableFilter, opts ...platform.FindOptions) ([]*platform.Variable, error) {
return []*platform.Variable{
{
ID: itesting.MustIDBase16("6162207574726f71"),
OrganizationID: platform2.ID(1),
Name: "variable-a",
Selected: []string{"b"},
Arguments: &platform.VariableArguments{
Type: "constant",
Values: platform.VariableConstantValues{"a", "b"},
},
CRUDLog: platform.CRUDLog{
CreatedAt: faketime,
UpdatedAt: faketime,
},
},
{
ID: itesting.MustIDBase16("61726920617a696f"),
OrganizationID: platform2.ID(1),
Name: "variable-b",
Selected: []string{"c"},
Arguments: &platform.VariableArguments{
Type: "map",
Values: platform.VariableMapValues{"a": "b", "c": "d"},
},
CRUDLog: platform.CRUDLog{
CreatedAt: faketime,
UpdatedAt: faketime,
},
},
}, nil
},
},
&mock.LabelService{
FindResourceLabelsFn: func(ctx context.Context, f platform.LabelMappingFilter) ([]*platform.Label, error) {
labels := []*platform.Label{
{
ID: itesting.MustIDBase16("fc3dc670a4be9b9a"),
Name: "label",
Properties: map[string]string{
"color": "fff000",
},
},
}
return labels, nil
},
},
},
wants: wants{
statusCode: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: `{
"links":{
"self":"/api/v2/variables?descending=false&limit=` + strconv.Itoa(platform.DefaultPageSize) + `&offset=0"
},
"variables":[
{
"arguments":{
"type":"constant",
"values":[
"a",
"b"
]
},
"createdAt": "2006-05-04T01:02:03Z",
"updatedAt": "2006-05-04T01:02:03Z",
"description":"",
"id":"6162207574726f71",
"labels":[
{
"id":"fc3dc670a4be9b9a",
"name":"label",
"properties":{
"color":"fff000"
}
}
],
"links":{
"labels":"/api/v2/variables/6162207574726f71/labels",
"org":"/api/v2/orgs/0000000000000001",
"self":"/api/v2/variables/6162207574726f71"
},
"name":"variable-a",
"orgID":"0000000000000001",
"selected":[
"b"
]
},
{
"arguments":{
"type":"map",
"values":{
"a":"b",
"c":"d"
}
},
"createdAt": "2006-05-04T01:02:03Z",
"updatedAt": "2006-05-04T01:02:03Z",
"description":"",
"id":"61726920617a696f",
"labels":[
{
"id":"fc3dc670a4be9b9a",
"name":"label",
"properties":{
"color":"fff000"
}
}
],
"links":{
"labels":"/api/v2/variables/61726920617a696f/labels",
"org":"/api/v2/orgs/0000000000000001",
"self":"/api/v2/variables/61726920617a696f"
},
"name":"variable-b",
"orgID":"0000000000000001",
"selected":[
"c"
]
}
]
}`,
},
},
{
name: "get all variables when there are none",
fields: fields{
&mock.VariableService{
FindVariablesF: func(ctx context.Context, filter platform.VariableFilter, opts ...platform.FindOptions) ([]*platform.Variable, error) {
return []*platform.Variable{}, nil
},
},
&mock.LabelService{
FindResourceLabelsFn: func(ctx context.Context, f platform.LabelMappingFilter) ([]*platform.Label, error) {
return []*platform.Label{}, nil
},
},
},
args: args{
map[string][]string{
"limit": {"1"},
},
},
wants: wants{
statusCode: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: `{"links":{"self":"/api/v2/variables?descending=false&limit=1&offset=0"},"variables":[]}`,
},
},
{
name: "get all variables belonging to an org",
fields: fields{
&mock.VariableService{
FindVariablesF: func(ctx context.Context, filter platform.VariableFilter, opts ...platform.FindOptions) ([]*platform.Variable, error) {
return []*platform.Variable{
{
ID: itesting.MustIDBase16("6162207574726f71"),
OrganizationID: itesting.MustIDBase16("0000000000000001"),
Name: "variable-a",
Selected: []string{"b"},
Arguments: &platform.VariableArguments{
Type: "constant",
Values: platform.VariableConstantValues{"a", "b"},
},
CRUDLog: platform.CRUDLog{
CreatedAt: faketime,
UpdatedAt: faketime,
},
},
}, nil
},
},
&mock.LabelService{
FindResourceLabelsFn: func(ctx context.Context, f platform.LabelMappingFilter) ([]*platform.Label, error) {
labels := []*platform.Label{
{
ID: itesting.MustIDBase16("fc3dc670a4be9b9a"),
Name: "label",
Properties: map[string]string{
"color": "fff000",
},
},
}
return labels, nil
},
},
},
args: args{
map[string][]string{
"orgID": {"0000000000000001"},
},
},
wants: wants{
statusCode: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: `{
"links": {
"self": "/api/v2/variables?descending=false&limit=` + strconv.Itoa(platform.DefaultPageSize) + `&offset=0&orgID=0000000000000001"
},
"variables": [
{
"arguments": {
"type": "constant",
"values": [
"a",
"b"
]
},
"description": "",
"id": "6162207574726f71",
"labels": [
{
"id": "fc3dc670a4be9b9a",
"name": "label",
"properties": {
"color": "fff000"
}
}
],
"links": {
"labels": "/api/v2/variables/6162207574726f71/labels",
"org": "/api/v2/orgs/0000000000000001",
"self": "/api/v2/variables/6162207574726f71"
},
"name": "variable-a",
"orgID": "0000000000000001",
"selected": [
"b"
],
"createdAt": "2006-05-04T01:02:03Z",
"updatedAt": "2006-05-04T01:02:03Z"
}
]
}`,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
variableBackend := NewMockVariableBackend(t)
variableBackend.HTTPErrorHandler = kithttp.NewErrorHandler(zaptest.NewLogger(t))
variableBackend.LabelService = tt.fields.LabelService
variableBackend.VariableService = tt.fields.VariableService
h := NewVariableHandler(zaptest.NewLogger(t), variableBackend)
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()
w := httptest.NewRecorder()
h.handleGetVariables(w, r)
res := w.Result()
contentType := res.Header.Get("Content-Type")
body, _ := io.ReadAll(res.Body)
if res.StatusCode != tt.wants.statusCode {
t.Errorf("%q. handleGetVariables() = %v, want %v", tt.name, res.StatusCode, tt.wants.statusCode)
}
if contentType != tt.wants.contentType {
t.Errorf("%q. handleGetVariables() = %v, want %v", tt.name, contentType, tt.wants.contentType)
}
if eq, diff, err := jsonEqual(string(body), tt.wants.body); err != nil {
t.Errorf("%q, handleGetDashboards(). error unmarshalling json %v", tt.name, err)
} else if tt.wants.body != "" && !eq {
t.Errorf("%q. handleGetDashboards() = ***%s***", tt.name, diff)
}
})
}
}
func TestVariableService_handleGetVariable(t *testing.T) {
type fields struct {
VariableService platform.VariableService
}
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 variable by id",
args: args{
id: "75650d0a636f6d70",
},
fields: fields{
&mock.VariableService{
FindVariableByIDF: func(ctx context.Context, id platform2.ID) (*platform.Variable, error) {
return &platform.Variable{
ID: itesting.MustIDBase16("75650d0a636f6d70"),
OrganizationID: platform2.ID(1),
Name: "variable-a",
Selected: []string{"b"},
Arguments: &platform.VariableArguments{
Type: "constant",
Values: platform.VariableConstantValues{"a", "b"},
},
CRUDLog: platform.CRUDLog{
CreatedAt: faketime,
UpdatedAt: faketime,
},
}, nil
},
},
},
wants: wants{
statusCode: 200,
contentType: "application/json; charset=utf-8",
body: `{"id":"75650d0a636f6d70","orgID":"0000000000000001","name":"variable-a","description":"","selected":["b"],"arguments":{"type":"constant","values":["a","b"]},"createdAt":"2006-05-04T01:02:03Z","updatedAt":"2006-05-04T01:02:03Z","labels":[],"links":{"self":"/api/v2/variables/75650d0a636f6d70","labels":"/api/v2/variables/75650d0a636f6d70/labels","org":"/api/v2/orgs/0000000000000001"}}`,
},
},
{
name: "get a non-existent variable",
args: args{
id: "75650d0a636f6d70",
},
fields: fields{
&mock.VariableService{
FindVariableByIDF: func(ctx context.Context, id platform2.ID) (*platform.Variable, error) {
return nil, &errors.Error{
Code: errors.ENotFound,
Msg: fmt.Sprintf("variable with ID %v not found", id),
}
},
},
},
wants: wants{
statusCode: 404,
contentType: "application/json; charset=utf-8",
body: `{"code":"not found","message":"variable with ID 75650d0a636f6d70 not found"}`,
},
},
{
name: "request an invalid variable ID",
args: args{
id: "baz",
},
fields: fields{
&mock.VariableService{
FindVariableByIDF: func(ctx context.Context, id platform2.ID) (*platform.Variable, error) {
return nil, nil
},
},
},
wants: wants{
statusCode: 400,
contentType: "application/json; charset=utf-8",
body: `{"code":"invalid","message":"id must have a length of 16 bytes"}`,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
variableBackend := NewMockVariableBackend(t)
variableBackend.HTTPErrorHandler = kithttp.NewErrorHandler(zaptest.NewLogger(t))
variableBackend.VariableService = tt.fields.VariableService
h := NewVariableHandler(zaptest.NewLogger(t), variableBackend)
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.handleGetVariable(w, r)
res := w.Result()
contentType := res.Header.Get("Content-Type")
bodyBytes, _ := io.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 eq, diff, err := jsonEqual(string(body), tt.wants.body); err != nil {
t.Errorf("%q, error unmarshalling json %v", tt.name, err)
} else if tt.wants.body != "" && !eq {
t.Errorf("%q. ***%s***", tt.name, diff)
}
})
}
}
func TestVariableService_handlePostVariable(t *testing.T) {
type fields struct {
VariableService platform.VariableService
}
type args struct {
variable string
}
type wants struct {
statusCode int
contentType string
body string
}
tests := []struct {
name string
fields fields
args args
wants wants
}{
{
name: "create a new variable",
fields: fields{
&mock.VariableService{
CreateVariableF: func(ctx context.Context, m *platform.Variable) error {
m.ID = itesting.MustIDBase16("75650d0a636f6d70")
m.OrganizationID = platform2.ID(1)
m.UpdatedAt = faketime
m.CreatedAt = faketime
return nil
},
},
},
args: args{
variable: `
{
"name": "my-great-variable",
"orgID": "0000000000000001",
"arguments": {
"type": "constant",
"values": [
"bar",
"foo"
]
},
"selected": [
"'foo'"
],
"createdAt": "2006-05-04T01:02:03Z",
"updatedAt": "2006-05-04T01:02:03Z"
}
`,
},
wants: wants{
statusCode: 201,
contentType: "application/json; charset=utf-8",
body: `{"id":"75650d0a636f6d70","orgID":"0000000000000001","name":"my-great-variable","description":"","selected":["'foo'"],"arguments":{"type":"constant","values":["bar","foo"]},"createdAt":"2006-05-04T01:02:03Z","updatedAt":"2006-05-04T01:02:03Z","labels":[],"links":{"self":"/api/v2/variables/75650d0a636f6d70","labels":"/api/v2/variables/75650d0a636f6d70/labels","org":"/api/v2/orgs/0000000000000001"}}
`,
},
},
{
name: "create a variable with invalid fields",
fields: fields{
&mock.VariableService{
CreateVariableF: func(ctx context.Context, m *platform.Variable) error {
m.ID = itesting.MustIDBase16("0")
return nil
},
},
},
args: args{
variable: `{"data": "nonsense"}`,
},
wants: wants{
statusCode: 400,
contentType: "application/json; charset=utf-8",
body: `{"code":"invalid","message":"missing variable name"}`,
},
},
{
name: "create a variable with invalid json",
fields: fields{
&mock.VariableService{
CreateVariableF: func(ctx context.Context, m *platform.Variable) error {
m.ID = itesting.MustIDBase16("0")
return nil
},
},
},
args: args{
variable: `howdy`,
},
wants: wants{
statusCode: 400,
contentType: "application/json; charset=utf-8",
body: `{"code":"invalid","message":"invalid character 'h' looking for beginning of value"}`,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
variableBackend := NewMockVariableBackend(t)
variableBackend.HTTPErrorHandler = kithttp.NewErrorHandler(zaptest.NewLogger(t))
variableBackend.VariableService = tt.fields.VariableService
h := NewVariableHandler(zaptest.NewLogger(t), variableBackend)
r := httptest.NewRequest("GET", "http://howdy.tld", bytes.NewReader([]byte(tt.args.variable)))
w := httptest.NewRecorder()
h.handlePostVariable(w, r)
res := w.Result()
contentType := res.Header.Get("Content-Type")
bodyBytes, _ := io.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 eq, diff, err := jsonEqual(string(body), tt.wants.body); err != nil {
t.Errorf("%q, error unmarshalling json %v", tt.name, err)
} else if tt.wants.body != "" && !eq {
t.Errorf("%q. ***%s***", tt.name, diff)
}
})
}
}
func TestVariableService_handlePutVariable(t *testing.T) {
type fields struct {
VariableService platform.VariableService
}
type args struct {
id string
variable string
}
type wants struct {
statusCode int
contentType string
body string
}
tests := []struct {
name string
fields fields
args args
wants wants
}{
{
name: "PUT a variable",
fields: fields{
&mock.VariableService{
ReplaceVariableF: func(ctx context.Context, m *platform.Variable) error {
m.ID = itesting.MustIDBase16("75650d0a636f6d70")
m.OrganizationID = platform2.ID(1)
m.UpdatedAt = faketime
m.CreatedAt = faketime
return nil
},
},
},
args: args{
id: "75650d0a636f6d70",
variable: `
{
"name": "my-great-variable",
"orgID": "0000000000000001",
"arguments": {
"type": "constant",
"values": [
"bar",
"foo"
]
},
"selected": [
"'foo'"
],
"createdAt": "2006-05-04T01:02:03Z",
"updatedAt": "2006-05-04T01:02:03Z"
}
`,
},
wants: wants{
statusCode: 200,
contentType: "application/json; charset=utf-8",
body: `{"id":"75650d0a636f6d70","orgID":"0000000000000001","name":"my-great-variable","description":"","selected":["'foo'"],"arguments":{"type":"constant","values":["bar","foo"]},"createdAt":"2006-05-04T01:02:03Z","updatedAt":"2006-05-04T01:02:03Z","labels":[],"links":{"self":"/api/v2/variables/75650d0a636f6d70","labels":"/api/v2/variables/75650d0a636f6d70/labels","org":"/api/v2/orgs/0000000000000001"}}
`,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
variableBackend := NewMockVariableBackend(t)
variableBackend.HTTPErrorHandler = kithttp.NewErrorHandler(zaptest.NewLogger(t))
variableBackend.VariableService = tt.fields.VariableService
h := NewVariableHandler(zaptest.NewLogger(t), variableBackend)
r := httptest.NewRequest("GET", "http://howdy.tld", bytes.NewReader([]byte(tt.args.variable)))
r = r.WithContext(context.WithValue(
context.TODO(),
httprouter.ParamsKey,
httprouter.Params{
{
Key: "id",
Value: tt.args.id,
},
}))
w := httptest.NewRecorder()
h.handlePutVariable(w, r)
res := w.Result()
contentType := res.Header.Get("Content-Type")
bodyBytes, _ := io.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 eq, diff, err := jsonEqual(string(body), tt.wants.body); err != nil {
t.Errorf("%q, error unmarshalling json %v", tt.name, err)
} else if tt.wants.body != "" && !eq {
t.Errorf("%q. ***%s***", tt.name, diff)
}
})
}
}
func TestVariableService_handlePatchVariable(t *testing.T) {
type fields struct {
VariableService platform.VariableService
}
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 variable name",
fields: fields{
&mock.VariableService{
UpdateVariableF: func(ctx context.Context, id platform2.ID, u *platform.VariableUpdate) (*platform.Variable, error) {
return &platform.Variable{
ID: itesting.MustIDBase16("75650d0a636f6d70"),
OrganizationID: platform2.ID(2),
Name: "new-name",
Arguments: &platform.VariableArguments{
Type: "constant",
Values: platform.VariableConstantValues{},
},
Selected: []string{},
CRUDLog: platform.CRUDLog{
CreatedAt: faketime,
UpdatedAt: faketime,
},
}, nil
},
},
},
args: args{
id: "75650d0a636f6d70",
update: `{"name": "new-name"}`,
},
wants: wants{
statusCode: 200,
contentType: "application/json; charset=utf-8",
body: `{"id":"75650d0a636f6d70","orgID":"0000000000000002","name":"new-name","description":"","selected":[],"arguments":{"type":"constant","values":[]},"createdAt":"2006-05-04T01:02:03Z","updatedAt": "2006-05-04T01:02:03Z","labels":[],"links":{"self":"/api/v2/variables/75650d0a636f6d70","labels":"/api/v2/variables/75650d0a636f6d70/labels","org":"/api/v2/orgs/0000000000000002"}}`,
},
},
{
name: "with an empty json body",
fields: fields{
&mock.VariableService{},
},
args: args{
id: "75650d0a636f6d70",
update: `{}`,
},
wants: wants{
statusCode: 400,
contentType: "application/json; charset=utf-8",
body: `{"code":"invalid","message":"no fields supplied in update"}`,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
variableBackend := NewMockVariableBackend(t)
variableBackend.HTTPErrorHandler = kithttp.NewErrorHandler(zaptest.NewLogger(t))
variableBackend.VariableService = tt.fields.VariableService
h := NewVariableHandler(zaptest.NewLogger(t), variableBackend)
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.handlePatchVariable(w, r)
res := w.Result()
contentType := res.Header.Get("Content-Type")
bodyBytes, _ := io.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 eq, diff, err := jsonEqual(string(body), tt.wants.body); err != nil {
t.Errorf("%q, error unmarshalling json %v", tt.name, err)
} else if tt.wants.body != "" && !eq {
t.Errorf("%q. ***%s***", tt.name, diff)
}
})
}
}
func TestVariableService_handleDeleteVariable(t *testing.T) {
type fields struct {
VariableService platform.VariableService
}
type args struct {
id string
}
type wants struct {
statusCode int
}
tests := []struct {
name string
fields fields
args args
wants wants
}{
{
name: "delete a variable",
fields: fields{
&mock.VariableService{
DeleteVariableF: func(ctx context.Context, id platform2.ID) error {
return nil
},
},
},
args: args{
id: "75650d0a636f6d70",
},
wants: wants{
statusCode: 204,
},
},
{
name: "delete a non-existent variable",
fields: fields{
&mock.VariableService{
DeleteVariableF: func(ctx context.Context, id platform2.ID) error {
return &errors.Error{
Code: errors.ENotFound,
Msg: fmt.Sprintf("variable with ID %v not found", id),
}
},
},
},
args: args{
id: "75650d0a636f6d70",
},
wants: wants{
statusCode: 404,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
variableBackend := NewMockVariableBackend(t)
variableBackend.HTTPErrorHandler = kithttp.NewErrorHandler(zaptest.NewLogger(t))
variableBackend.VariableService = tt.fields.VariableService
h := NewVariableHandler(zaptest.NewLogger(t), variableBackend)
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.handleDeleteVariable(w, r)
statusCode := w.Result().StatusCode
if statusCode != tt.wants.statusCode {
t.Errorf("got = %v, want %v", statusCode, tt.wants.statusCode)
}
})
}
}
func TestService_handlePostVariableLabel(t *testing.T) {
type fields struct {
LabelService platform.LabelService
}
type args struct {
labelMapping *platform.LabelMapping
variableID platform2.ID
}
type wants struct {
statusCode int
contentType string
body string
}
tests := []struct {
name string
fields fields
args args
wants wants
}{
{
name: "add label to variable",
fields: fields{
LabelService: &mock.LabelService{
FindLabelByIDFn: func(ctx context.Context, id platform2.ID) (*platform.Label, error) {
return &platform.Label{
ID: 1,
Name: "label",
Properties: map[string]string{
"color": "fff000",
},
}, nil
},
CreateLabelMappingFn: func(ctx context.Context, m *platform.LabelMapping) error { return nil },
},
},
args: args{
labelMapping: &platform.LabelMapping{
ResourceID: 100,
LabelID: 1,
},
variableID: 100,
},
wants: wants{
statusCode: http.StatusCreated,
contentType: "application/json; charset=utf-8",
body: `
{
"label": {
"id": "0000000000000001",
"name": "label",
"properties": {
"color": "fff000"
}
},
"links": {
"self": "/api/v2/labels/0000000000000001"
}
}
`,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
variableBackend := NewMockVariableBackend(t)
variableBackend.HTTPErrorHandler = kithttp.NewErrorHandler(zaptest.NewLogger(t))
variableBackend.LabelService = tt.fields.LabelService
h := NewVariableHandler(zaptest.NewLogger(t), variableBackend)
b, err := json.Marshal(tt.args.labelMapping)
if err != nil {
t.Fatalf("failed to unmarshal label mapping: %v", err)
}
url := fmt.Sprintf("http://localhost:8086/api/v2/variables/%s/labels", tt.args.variableID)
r := httptest.NewRequest("POST", url, bytes.NewReader(b))
w := httptest.NewRecorder()
h.ServeHTTP(w, r)
res := w.Result()
content := res.Header.Get("Content-Type")
body, _ := io.ReadAll(res.Body)
if res.StatusCode != tt.wants.statusCode {
t.Errorf("got %v, want %v", res.StatusCode, tt.wants.statusCode)
}
if tt.wants.contentType != "" && content != tt.wants.contentType {
t.Errorf("got %v, want %v", content, tt.wants.contentType)
}
if eq, diff, err := jsonEqual(string(body), tt.wants.body); err != nil {
t.Errorf("%q, error unmarshalling json %v", tt.name, err)
} else if tt.wants.body != "" && !eq {
t.Errorf("%q. ***%s***", tt.name, diff)
}
})
}
}
func initVariableService(f itesting.VariableFields, t *testing.T) (platform.VariableService, string, func()) {
store := itesting.NewTestInmemStore(t)
tenantService := tenant.NewService(tenant.NewStore(store))
svc := kv.NewService(zaptest.NewLogger(t), store, tenantService)
svc.IDGenerator = f.IDGenerator
svc.TimeGenerator = f.TimeGenerator
ctx := context.Background()
for _, v := range f.Variables {
if err := svc.ReplaceVariable(ctx, v); err != nil {
t.Fatalf("failed to replace variable: %v", err)
}
}
fakeBackend := NewMockVariableBackend(t)
fakeBackend.VariableService = svc
handler := NewVariableHandler(zaptest.NewLogger(t), fakeBackend)
server := httptest.NewServer(handler)
client := VariableService{
Client: mustNewHTTPClient(t, server.URL, ""),
}
done := server.Close
return &client, "", done
}
func TestVariableService(t *testing.T) {
itesting.VariableService(initVariableService, t, itesting.WithHTTPValidation())
}