influxdb/notification/check/check_test.go

284 lines
7.2 KiB
Go

package check_test
import (
"encoding/json"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/influxdata/flux/ast"
"github.com/influxdata/flux/ast/astutil"
"github.com/influxdata/flux/parser"
"github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/kit/platform/errors"
"github.com/influxdata/influxdb/v2/mock"
"github.com/influxdata/influxdb/v2/notification"
"github.com/influxdata/influxdb/v2/notification/check"
"github.com/influxdata/influxdb/v2/query/fluxlang"
influxTesting "github.com/influxdata/influxdb/v2/testing"
"github.com/stretchr/testify/require"
)
const (
id1 = "020f755c3c082000"
id2 = "020f755c3c082001"
id3 = "020f755c3c082002"
)
var goodBase = check.Base{
ID: influxTesting.MustIDBase16(id1),
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
StatusMessageTemplate: "temp1",
Every: mustDuration("1m"),
Tags: []influxdb.Tag{
{Key: "k1", Value: "v1"},
{Key: "k2", Value: "v2"},
},
}
func TestValidCheck(t *testing.T) {
cases := []struct {
name string
src influxdb.Check
err error
}{
{
name: "invalid check id",
src: &check.Deadman{},
err: &errors.Error{
Code: errors.EInvalid,
Msg: "Check ID is invalid",
},
},
{
name: "empty name",
src: &check.Threshold{
Base: check.Base{
ID: influxTesting.MustIDBase16(id1),
},
},
err: &errors.Error{
Code: errors.EInvalid,
Msg: "Check Name can't be empty",
},
},
{
name: "invalid org id",
src: &check.Threshold{
Base: check.Base{
ID: influxTesting.MustIDBase16(id1),
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
},
},
err: &errors.Error{
Code: errors.EInvalid,
Msg: "Check OrgID is invalid",
},
},
{
name: "nil every",
src: &check.Deadman{
Base: check.Base{
ID: influxTesting.MustIDBase16(id1),
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
StatusMessageTemplate: "temp1",
Tags: []influxdb.Tag{{Key: "key1"}},
},
},
err: &errors.Error{
Code: errors.EInvalid,
Msg: "Check Every must exist",
},
},
{
name: "offset greater then interval",
src: &check.Deadman{
Base: check.Base{
ID: influxTesting.MustIDBase16(id1),
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
Every: mustDuration("1m"),
Offset: mustDuration("2m"),
},
},
err: &errors.Error{
Code: errors.EInvalid,
Msg: "Offset should not be equal or greater than the interval",
},
},
{
name: "invalid tag",
src: &check.Deadman{
Base: check.Base{
ID: influxTesting.MustIDBase16(id1),
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
StatusMessageTemplate: "temp1",
Every: mustDuration("1m"),
Tags: []influxdb.Tag{{Key: "key1"}},
},
},
err: &errors.Error{
Code: errors.EInvalid,
Msg: "tag must contain a key and a value",
},
},
{
name: "bad threshold",
src: &check.Threshold{
Base: goodBase,
Thresholds: []check.ThresholdConfig{
&check.Range{Min: 200, Max: 100},
},
},
err: &errors.Error{
Code: errors.EInvalid,
Msg: "range threshold min can't be larger than max",
},
},
}
for _, c := range cases {
got := c.src.Valid(fluxlang.DefaultService)
influxTesting.ErrorsEqual(t, got, c.err)
}
}
var timeGen1 = mock.TimeGenerator{FakeValue: time.Date(2006, time.July, 13, 4, 19, 10, 0, time.UTC)}
var timeGen2 = mock.TimeGenerator{FakeValue: time.Date(2006, time.July, 14, 5, 23, 53, 10, time.UTC)}
func mustDuration(d string) *notification.Duration {
dur, err := parser.ParseDuration(d)
if err != nil {
panic(err)
}
return (*notification.Duration)(dur)
}
func TestJSON(t *testing.T) {
cases := []struct {
name string
src influxdb.Check
}{
{
name: "simple Deadman",
src: &check.Deadman{
Base: check.Base{
ID: influxTesting.MustIDBase16(id1),
OwnerID: influxTesting.MustIDBase16(id2),
Name: "name1",
OrgID: influxTesting.MustIDBase16(id3),
Every: mustDuration("1h"),
Query: influxdb.DashboardQuery{
BuilderConfig: influxdb.BuilderConfig{
Buckets: []string{},
Tags: []struct {
Key string `json:"key"`
Values []string `json:"values"`
AggregateFunctionType string `json:"aggregateFunctionType"`
}{},
Functions: []struct {
Name string `json:"name"`
}{},
},
},
Tags: []influxdb.Tag{
{
Key: "k1",
Value: "v1",
},
{
Key: "k2",
Value: "v2",
},
},
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
TimeSince: mustDuration("33s"),
ReportZero: true,
Level: notification.Warn,
},
},
{
name: "simple threshold",
src: &check.Threshold{
Base: check.Base{
ID: influxTesting.MustIDBase16(id1),
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
Every: mustDuration("1h"),
Query: influxdb.DashboardQuery{
BuilderConfig: influxdb.BuilderConfig{
Buckets: []string{},
Tags: []struct {
Key string `json:"key"`
Values []string `json:"values"`
AggregateFunctionType string `json:"aggregateFunctionType"`
}{},
Functions: []struct {
Name string `json:"name"`
}{},
},
},
Tags: []influxdb.Tag{
{
Key: "k1",
Value: "v1",
},
{
Key: "k2",
Value: "v2",
},
},
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
Thresholds: []check.ThresholdConfig{
&check.Greater{ThresholdConfigBase: check.ThresholdConfigBase{AllValues: true}, Value: -1.36},
&check.Range{Min: -10000, Max: 500},
&check.Lesser{ThresholdConfigBase: check.ThresholdConfigBase{Level: notification.Critical}},
},
},
},
}
for _, c := range cases {
fn := func(t *testing.T) {
b, err := json.Marshal(c.src)
if err != nil {
t.Fatalf("%s marshal failed, err: %s", c.name, err.Error())
}
got, err := check.UnmarshalJSON(b)
if err != nil {
t.Fatalf("%s unmarshal failed, err: %s", c.name, err.Error())
}
if diff := cmp.Diff(got, c.src, cmpopts.IgnoreFields(notification.Duration{}, "BaseNode")); diff != "" {
t.Errorf("failed %s, Check are different -got/+want\ndiff %s", c.name, diff)
}
}
t.Run(c.name, fn)
}
}
func mustFormatPackage(t *testing.T, pkg *ast.Package) string {
if len(pkg.Files) == 0 {
t.Fatal("package expected to have at least one file")
}
v, err := astutil.Format(pkg.Files[0])
require.NoError(t, err)
return v
}